| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot apply [PSerializable] to type '<Type>' because the base constructor '<BaseConstructor>' is not accessible from '<Type>'. |
Cause
[PSerializableAttribute] generates a deserializing constructor in <Type>, which PortableFormatter calls to create the instance before it restores its fields. This constructor calls <BaseConstructor>, a constructor of the base type:
- the deserializing constructor of the base type, which has a single parameter of type
PortableFormatterConstructorContext, when the base type has one; - otherwise, when the base type is marked
[Serializer(null)]because it has no state to serialize, its parameterless constructor.
PostSharp reports SR0003 when <BaseConstructor> is not accessible from <Type>, for example when it is private, or internal in another assembly. PostSharp reports the message on <Type>, not on the constructor of the base type, and shows <BaseConstructor> without its parameters, as Entity.#ctor.
In the following example, Entity has no serializer, and its parameterless constructor is private, so the deserializing constructor of Customer cannot call it.
using System;
using System.IO;
using PostSharp.Serialization;
namespace Errors.SR0003_Error;
// Entity has no state to serialize, so it has no serializer.
[Serializer( null )]
public abstract class Entity
{
// Derived classes must give a name, which this constructor does not check.
private Entity()
{
}
protected Entity( string name )
{
if ( string.IsNullOrEmpty( name ) )
{
throw new ArgumentException( "The name cannot be empty.", nameof(name) );
}
}
}
[PSerializable]
public class Customer : Entity // The parameterless constructor of Entity is private.
{
public Customer( string name ) : base( name )
{
this.Name = name;
}
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( "Alice" ), stream );
stream.Position = 0;
var customer = (Customer) formatter.Deserialize( stream );
Console.WriteLine( $"Customer {customer.Name}" );
}
}
error SR0003: SR0003_Error.cs(26,14): Cannot apply [PSerializable] to type 'Errors.SR0003_Error.Customer' because the base constructor 'Errors.SR0003_Error.Entity.#ctor' is not accessible from 'Errors.SR0003_Error.Customer'.
Resolution
Make <BaseConstructor> accessible from the derived type: protected is enough. When the base type is in another assembly, internal is not enough.
In the following example, the parameterless constructor of Entity is protected, and a Customer is serialized and deserialized with PortableFormatter.
using System;
using System.IO;
using PostSharp.Serialization;
namespace Errors.SR0003_Fixed;
// Entity has no state to serialize, so it has no serializer.
[Serializer( null )]
public abstract class Entity
{
// The deserializing constructor of a derived class calls this constructor.
protected Entity()
{
}
protected Entity( string name )
{
if ( string.IsNullOrEmpty( name ) )
{
throw new ArgumentException( "The name cannot be empty.", nameof(name) );
}
}
}
[PSerializable]
public class Customer : Entity
{
public Customer( string name ) : base( name )
{
this.Name = name;
}
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( "Alice" ), stream );
stream.Position = 0;
var customer = (Customer) formatter.Deserialize( stream );
Console.WriteLine( $"Customer {customer.Name}" );
}
}
Customer Alice
See Also
Reference
PSerializableAttribute
SerializerAttribute
PortableFormatter
Other Resources