| Severity | Error |
| Reported by | PostSharp |
| Message | Conflicting aspects on "<Declaration>": <Reason>. |
Cause
The dependencies of an aspect class, AspectTypeDependencyAttribute, AspectRoleDependencyAttribute and AspectEffectDependencyAttribute, can do more than order aspects. PostSharp checks them once it has ordered the aspects of a declaration, and reports PS0112 in two cases:
- A dependency with the Conflict action matches another aspect on the same declaration: another aspect type, another aspect that provides a role, or another aspect that has an effect. With a position, the conflict exists only when the other aspect runs before (
After) or after (Before) the current one.<Reason>then says that the first transformationcannot be used together with,cannot be preceded byorcannot be followed bythe second. - A dependency with the Require action matches no other aspect on the declaration, or none at the required position.
<Reason>then says that the transformationmust be used together with,must be preceded byormust be followed bya transformation that matches the condition.
Dependencies between transformations of the same aspect instance are ignored. PS0112 is an error, or a warning when the IsWarning property of the dependency is true.
In the following example, both caching aspects conflict with any other aspect that provides the caching role, and both are applied to GetProductName.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Dependencies;
using PostSharp.Serialization;
namespace Errors.PS0112_Error;
// A method can have only one caching aspect.
[PSerializable]
[ProvideAspectRole( StandardRoles.Caching )]
[AspectRoleDependency( AspectDependencyAction.Conflict, StandardRoles.Caching )]
public class MemoryCacheAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( "Look up the memory cache" );
}
[PSerializable]
[ProvideAspectRole( StandardRoles.Caching )]
[AspectRoleDependency( AspectDependencyAction.Conflict, StandardRoles.Caching )]
public class DiskCacheAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( "Look up the disk cache" );
}
public class ProductCatalog
{
[MemoryCache]
[DiskCache] // A second caching aspect on the same method.
public string GetProductName( int id )
{
return id == 1 ? "Coffee" : "Tea";
}
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new ProductCatalog().GetProductName( 1 ) );
}
}
error PS0112: PS0112_Error.cs(29,19): Conflicting aspects on "Errors.PS0112_Error.ProductCatalog.GetProductName(System.Int32)": 'Errors.PS0112_Error.MemoryCacheAttribute: Marker BEFORE (2)' cannot be used together with 'Errors.PS0112_Error.DiskCacheAttribute: Marker BEFORE (3)' because the second provides the role 'Caching'.
Resolution
- For a conflict, remove one of the conflicting aspects from the declaration, or exclude it from this declaration with AttributeExclude when the aspect is multicast. When the conflict depends on a position, change the order of the aspects so that the conflicting aspect is on the allowed side.
- For a requirement, add the aspect that the dependency requires, at the required position.
- When the aspects are yours and the combination is valid, remove the dependency, or give it a position that describes the actual problem.
In the following example, the method keeps only the memory cache.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Dependencies;
using PostSharp.Serialization;
namespace Errors.PS0112_Fixed;
// A method can have only one caching aspect.
[PSerializable]
[ProvideAspectRole( StandardRoles.Caching )]
[AspectRoleDependency( AspectDependencyAction.Conflict, StandardRoles.Caching )]
public class MemoryCacheAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( "Look up the memory cache" );
}
[PSerializable]
[ProvideAspectRole( StandardRoles.Caching )]
[AspectRoleDependency( AspectDependencyAction.Conflict, StandardRoles.Caching )]
public class DiskCacheAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( "Look up the disk cache" );
}
public class ProductCatalog
{
[MemoryCache] // The only caching aspect of the method.
public string GetProductName( int id )
{
return id == 1 ? "Coffee" : "Tea";
}
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new ProductCatalog().GetProductName( 1 ) );
}
}
Look up the memory cache
Coffee
See Also
Reference
AspectDependencyAction
AspectRoleDependencyAttribute
ProvideAspectRoleAttribute
Other Resources