| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot find in the type "<AspectType>" a property or field named "<Name>" specified in the ObjectConstruction object. |
Cause
An IAspectProvider can describe the aspect that it provides with an ObjectConstruction instead of an instance. PostSharp then builds a custom attribute of type <AspectType> from this description, and sets each entry of NamedArguments as a property or a field of the attribute. The names are not checked when you create the ObjectConstruction, so a misspelled name shows up only at build time.
PostSharp reports PS0121 when a name <Name> is neither a property nor a field of the aspect class. The message has no location. PostSharp then reports LA0117, which names the aspect provider and the target of the aspect, and skips the aspect.
In the following example, the [LogPublicMethods] aspect provider sets Categry instead of the Category property of LogAttribute.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;
using BindingFlags = System.Reflection.BindingFlags;
namespace Errors.PS0121_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public string Category { get; set; } = "Default";
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"[{this.Category}] Entering {args.Method.Name}." );
}
// Logs the public methods of the target class.
[PSerializable]
public class LogPublicMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
Type type = (Type) targetElement;
foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
ObjectConstruction construction = new( typeof(LogAttribute) );
// LogAttribute has no property or field named Categry.
construction.NamedArguments["Categry"] = "Orders";
yield return new AspectInstance( method, construction );
}
}
}
[LogPublicMethods]
public class OrderService
{
public void PlaceOrder( string product ) => Console.WriteLine( $"Order for {product} placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair" );
}
}
error LA0117: PS0121_Error.cs(21,14): Cannot parse the ObjectConstruction provided by the aspect provider "Errors.PS0121_Error.LogPublicMethodsAttribute" applied on "Errors.PS0121_Error.OrderService.PlaceOrder(System.String)".
error PS0121: Cannot find in the type "Errors.PS0121_Error.LogAttribute" a property or field named "Categry" specified in the ObjectConstruction object.
Resolution
Use only the names of properties or fields of the aspect class as keys of NamedArguments. To get the name checked by the C# compiler, write it with the nameof operator, for example nameof(LogAttribute.Category).
In the following example, the named argument matches the Category property of LogAttribute.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;
using BindingFlags = System.Reflection.BindingFlags;
namespace Errors.PS0121_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public string Category { get; set; } = "Default";
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"[{this.Category}] Entering {args.Method.Name}." );
}
// Logs the public methods of the target class.
[PSerializable]
public class LogPublicMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
Type type = (Type) targetElement;
foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
ObjectConstruction construction = new( typeof(LogAttribute) );
// The name matches the Category property of LogAttribute.
construction.NamedArguments["Category"] = "Orders";
yield return new AspectInstance( method, construction );
}
}
}
[LogPublicMethods]
public class OrderService
{
public void PlaceOrder( string product ) => Console.WriteLine( $"Order for {product} placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair" );
}
}
[Orders] Entering PlaceOrder.
Order for Chair placed.
See Also
Reference
ObjectConstruction
IAspectProvider
AspectInstance
Other Resources