Open sandboxFocusImprove this doc

PS0106: Attribute Applied to an Excluded Kind of Parameter

Severity Error
Reported by PostSharp
Message Cannot apply the custom attribute "<AttributeType>" to parameter "<Parameter>" of method "<Method>": the attribute does not accept this kind of parameter (<ParameterKind>).

Cause

The AttributeTargetParameterAttributes property of a multicast attribute filters the parameters to which the attribute applies by the way they are passed: InParameter, OutParameter or RefParameter. When the attribute is multicast from a method or a type, PostSharp skips the parameters that the filter excludes. When the attribute is applied directly to an excluded parameter, PostSharp cannot skip it silently, and reports PS0106.

<ParameterKind> is the kind of the parameter that the filter excludes: out parameter, ref parameter, or input-only parameter, which also covers in parameters. The message has no location in the source code: it names the parameter and its method.

In the following example, the [NotEmpty] contract accepts only input parameters, but it is applied to the out parameter id.

using System;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.PS0106_Error;

[PSerializable]
public class NotEmptyAttribute : LocationLevelAspect, ILocationValidationAspect<string>
{
    public Exception? ValidateValue( string value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => string.IsNullOrEmpty( value ) ? new ArgumentException( $"The parameter {locationName} cannot be empty." ) : null;
}

public class CustomerDirectory
{
    public bool TryFindCustomer(
        [NotEmpty] string name,
        [NotEmpty( AttributeTargetParameterAttributes = MulticastAttributes.InParameter )] out string id ) // The filter accepts only input parameters, but this one is an out parameter.
    {
        id = name == "Alice" ? "C001" : "";

        return id.Length > 0;
    }
}

public static class Program
{
    public static void Main()
    {
        new CustomerDirectory().TryFindCustomer( "Alice", out var id );
        Console.WriteLine( $"Found customer {id}." );
    }
}
error PS0106: PS0106_Error.cs(20,103): Cannot apply the custom attribute "Errors.PS0106_Error.NotEmptyAttribute" to parameter "id : string&" of method "Errors.PS0106_Error.CustomerDirectory.TryFindCustomer(System.String, System.String@)": the attribute does not accept this kind of parameter (out parameter).

Resolution

  • Remove the attribute from the parameter that the filter excludes.
  • When the attribute must apply to this parameter, add its kind to the AttributeTargetParameterAttributes property, or remove the property. A validation aspect must then support this kind of parameter: an out parameter has no value when the method starts.
  • To apply the attribute to all the parameters of a kind, apply it to the method with the filter, and let PostSharp multicast it to the matching parameters.

In the following example, the contract validates only the input parameter name.

using System;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.PS0106_Fixed;

[PSerializable]
public class NotEmptyAttribute : LocationLevelAspect, ILocationValidationAspect<string>
{
    public Exception? ValidateValue( string value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => string.IsNullOrEmpty( value ) ? new ArgumentException( $"The parameter {locationName} cannot be empty." ) : null;
}

public class CustomerDirectory
{
    public bool TryFindCustomer(
        [NotEmpty] string name,
        out string id ) // The contract is no longer applied to the out parameter.
    {
        id = name == "Alice" ? "C001" : "";

        return id.Length > 0;
    }
}

public static class Program
{
    public static void Main()
    {
        new CustomerDirectory().TryFindCustomer( "Alice", out var id );
        Console.WriteLine( $"Found customer {id}." );

        try
        {
            new CustomerDirectory().TryFindCustomer( "", out _ );
        }
        catch ( ArgumentException e )
        {
            Console.WriteLine( e.Message );
        }
    }
}
Found customer C001.
The parameter name cannot be empty.

See Also

Reference

AttributeTargetParameterAttributes
MulticastAttributes
ILocationValidationAspect<T>

Other Resources

Adding Aspects to Multiple Declarations Using Attributes
Creating Custom Contracts