| Severity | Error |
| Reported by | PostSharp |
| Message | Aspect "<Aspect>" cannot be applied to method "<Method>" because it is an interface method without a default implementation. |
Cause
An OnMethodBoundaryAspect, an OnExceptionAspect or a MethodInterceptionAspect enhances the body of its target method, or redirects its calls to the aspect. A method of an interface that has no default implementation has no body, and the calls through the interface go to the classes that implement it. When one of these aspects targets such a method of the current project, PostSharp reports LA0130 and skips the aspect. An interface method with a default implementation, available since C# 8, is a valid target.
The usage of these aspect classes excludes abstract methods, so when you apply them as custom attributes, multicasting skips the interface methods without a default implementation. An aspect that an IAspectProvider provides is not filtered this way: its target is the declaration passed to the AspectInstance constructor. PostSharp then reports the message on the declaration that the provider is applied to.
In the following example, the [LogMethods] aspect provider is applied to the INotifier interface and passes all its methods to the [Log] aspect, including Send, which has no default implementation.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0130_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
[PSerializable]
public class LogMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
var type = (Type) targetElement;
foreach ( var method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
yield return new AspectInstance( method, new LogAttribute() );
}
}
}
// The provider passes Send, which has no default implementation, to the aspect.
[LogMethods]
public interface INotifier
{
void Send( string message );
void SendAll( params string[] messages )
{
foreach ( var message in messages )
{
this.Send( message );
}
}
}
public class ConsoleNotifier : INotifier
{
public void Send( string message ) => Console.WriteLine( $"Sent: {message}" );
}
public static class Program
{
public static void Main()
{
INotifier notifier = new ConsoleNotifier();
notifier.SendAll( "Order shipped", "Invoice ready" );
}
}
error LA0130: LA0130_Error.cs(34,18): Aspect "Errors.LA0130_Error.LogAttribute" cannot be applied to method "Errors.LA0130_Error.INotifier.Send(System.String)" because it is an interface method without a default implementation.
Resolution
- In the ProvideAspects method, skip the methods whose IsAbstract property is
true. - To enhance every implementation of the interface method, apply the aspect to the classes that implement the interface instead of the interface itself.
In the following example, the provider skips Send and enhances the default implementation of SendAll.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0130_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
[PSerializable]
public class LogMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
var type = (Type) targetElement;
foreach ( var method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
// Interface methods without a default implementation have no body to enhance, so they are skipped.
if ( !method.IsAbstract )
{
yield return new AspectInstance( method, new LogAttribute() );
}
}
}
}
[LogMethods]
public interface INotifier
{
void Send( string message );
void SendAll( params string[] messages )
{
foreach ( var message in messages )
{
this.Send( message );
}
}
}
public class ConsoleNotifier : INotifier
{
public void Send( string message ) => Console.WriteLine( $"Sent: {message}" );
}
public static class Program
{
public static void Main()
{
INotifier notifier = new ConsoleNotifier();
notifier.SendAll( "Order shipped", "Invoice ready" );
}
}
Entering SendAll.
Sent: Order shipped
Sent: Invoice ready
See Also
Reference
IAspectProvider
OnMethodBoundaryAspect
MethodInterceptionAspect
Other Resources
Adding Aspects Dynamically
Adding Aspects Programmatically Using IAspectProvider