| Severity | Error |
| Reported by | PostSharp |
| Message | Field '<Field>' must not be read-only because its declaring type is [PSerializable]. |
Cause
[PSerializableAttribute] serializes every instance field of the type, except the fields marked [PNonSerializedAttribute] and the fields of a delegate type. When PortableFormatter deserializes the object, the generated serializer first creates the instance, then assigns each of these fields. A readonly field can be assigned only in a constructor, so PostSharp reports SR0004 for the first read-only field that it would serialize.
The field can be a field that you wrote, or the backing field that C# generates for a get-only auto-property such as public string Name { get; }. In the second case, <Field> shows the name of the backing field, which contains the name of the property.
PostSharp reports the message on the type, not on the field. In the following example, the lines field of Order is read-only.
using System;
using System.Collections.Generic;
using System.IO;
using PostSharp.Serialization;
namespace Errors.SR0004_Error;
[PSerializable]
public class Order // The lines field of Order is read-only.
{
private readonly List<string> lines = new();
public void AddLine( string product ) => this.lines.Add( product );
public IReadOnlyList<string> Lines => this.lines;
}
public static class Program
{
public static void Main()
{
var order = new Order();
order.AddLine( "Keyboard" );
order.AddLine( "Mouse" );
var formatter = new PortableFormatter();
var stream = new MemoryStream();
formatter.Serialize( order, stream );
stream.Position = 0;
var copy = (Order) formatter.Deserialize( stream );
Console.WriteLine( $"Order with {string.Join( ", ", copy.Lines )}" );
}
}
error SR0004: SR0004_Error.cs(9,14): Field 'Errors.SR0004_Error.Order.lines' must not be read-only because its declaring type is [PSerializable].
Resolution
- Remove the
readonlymodifier of the field. For a get-only auto-property, add a setter, which can beprivate. - When the field does not need to be serialized, for example because it is computed from other fields, mark it with [PNonSerializedAttribute].
In the following example, the
linesfield is no longer read-only, and anOrderis serialized and deserialized with its lines.
using System;
using System.Collections.Generic;
using System.IO;
using PostSharp.Serialization;
namespace Errors.SR0004_Fixed;
[PSerializable]
public class Order
{
// The deserializer assigns this field, so it cannot be read-only.
private List<string> lines = new();
public void AddLine( string product ) => this.lines.Add( product );
public IReadOnlyList<string> Lines => this.lines;
}
public static class Program
{
public static void Main()
{
var order = new Order();
order.AddLine( "Keyboard" );
order.AddLine( "Mouse" );
var formatter = new PortableFormatter();
var stream = new MemoryStream();
formatter.Serialize( order, stream );
stream.Position = 0;
var copy = (Order) formatter.Deserialize( stream );
Console.WriteLine( $"Order with {string.Join( ", ", copy.Lines )}" );
}
}
Order with Keyboard, Mouse
See Also
Reference
PSerializableAttribute
PNonSerializedAttribute
PortableFormatter
Other Resources