| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot serialize the delegate type "<DelegateType>": fields of a delegate type in an aspect class must be marked as [NonSerialized]. |
Cause
PostSharp serializes the aspect instances at build time and deserializes them at run time. An aspect marked as [SerializableAttribute] instead of [PSerializableAttribute] is serialized with BinaryFormatter, which is allowed only when the PostSharpBinaryFormatterAllowed MSBuild property is True (otherwise PostSharp reports LA0206). A delegate refers to a method and often to a closure, which cannot be restored reliably in another process, so PostSharp refuses to serialize it.
PostSharp reports LA0149 when a field of a delegate type holds a delegate at the end of the build-time initialization of the aspect, for example because the constructor or CompileTimeInitialize assigns it. A field that is null at this time does not cause the message. <DelegateType> is the type of the delegate, such as System.Func`2<System.String,System.String>. The message has no location: look for the delegate fields of the [Serializable] aspects of the project.
In the following example, the constructor of the [Log] aspect assigns a lambda to a field.
// @BinaryFormatterAllowed
using System;
using PostSharp.Aspects;
namespace Errors.LA0149_Error;
[Serializable]
public class LogAttribute : OnMethodBoundaryAspect
{
// The delegate is serialized with the aspect.
private Func<string, string> format;
public LogAttribute()
{
this.format = name => $"Entering {name}.";
}
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( this.format( args.Method.Name ) );
}
public class OrderService
{
[Log]
public void PlaceOrder( string product ) => Console.WriteLine( $"Order placed: {product}" );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Book" );
}
}
error LA0149: Cannot serialize the delegate type "System.Func`2<System.String,System.String>": fields of a delegate type in an aspect class must be marked as [NonSerialized].
Resolution
Exclude the field from serialization and create the delegate at run time:
- Mark the field as [NonSerializedAttribute], and assign it in
RuntimeInitialize, which PostSharp calls at run time after deserializing the aspect. - Better, serialize the aspect with the portable serializer: replace [SerializableAttribute] with [PSerializableAttribute], and mark the field as [PNonSerializedAttribute].
BinaryFormatteris obsolete and is not available at run time on recent versions of .NET.
In the following example, the field is excluded from serialization and assigned in RuntimeInitialize(MethodBase). This program builds, but it does not run in an application that disables BinaryFormatter, which is the default on .NET 9 and later.
// @BinaryFormatterAllowed
// @SkipRuntime
using System;
using System.Reflection;
using PostSharp.Aspects;
namespace Errors.LA0149_Fixed;
[Serializable]
public class LogAttribute : OnMethodBoundaryAspect
{
// The delegate is excluded from serialization and created at run time.
[NonSerialized]
private Func<string, string>? format;
public override void RuntimeInitialize( MethodBase method )
{
this.format = name => $"Entering {name}.";
}
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( this.format!( args.Method.Name ) );
}
public class OrderService
{
[Log]
public void PlaceOrder( string product ) => Console.WriteLine( $"Order placed: {product}" );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Book" );
}
}
See Also
Reference
PSerializableAttribute
PNonSerializedAttribute
NonSerializedAttribute
Other Resources