Open sandboxFocusImprove this doc

LA0136: Validation Aspect on a Property Without Setter

Severity Error
Reported by PostSharp
Message Aspect "<Aspect>" cannot be applied to property "<Property>" because it is read-only.

Cause

An aspect that implements ILocationValidationAspect<T>, such as a contract, validates the values that are assigned to a field, a property or a parameter. For a property, PostSharp inserts the validation into the setter. When the property has no setter, for example a property with an expression body that only returns a field, there is no assignment to validate, so PostSharp reports LA0136.

In the following example, the [Positive] aspect is applied to the Quantity property, which only has a getter.

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

namespace Errors.LA0136_Error;

[PSerializable]
public class PositiveAttribute : LocationLevelAspect, ILocationValidationAspect<int>
{
    public Exception? ValidateValue( int value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => value <= 0 ? new ArgumentOutOfRangeException( locationName, $"{locationName} must be positive." ) : null;
}

public class OrderLine
{
    private int quantity;

    public OrderLine( int quantity )
    {
        this.quantity = quantity;
    }

    // The property has no setter, so no value is ever assigned to it.
    [Positive]
    public int Quantity => this.quantity;
}

public static class Program
{
    public static void Main()
    {
        try
        {
            var line = new OrderLine( 0 );
            Console.WriteLine( line.Quantity );
        }
        catch ( ArgumentOutOfRangeException e )
        {
            Console.WriteLine( e.Message );
        }
    }
}
error LA0136: LA0136_Error.cs(26,16): Aspect "Errors.LA0136_Error.PositiveAttribute" cannot be applied to property "Errors.LA0136_Error.OrderLine.Quantity" because it is read-only.

Resolution

  • Give the property a setter, which can be private, and assign the value through the property.
  • Otherwise, apply the aspect where the value is assigned: to the backing field, or to the parameter that receives the value.

In the following example, Quantity is an automatic property with a private setter, which the constructor assigns, so the aspect rejects the invalid quantity.

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

namespace Errors.LA0136_Fixed;

[PSerializable]
public class PositiveAttribute : LocationLevelAspect, ILocationValidationAspect<int>
{
    public Exception? ValidateValue( int value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => value <= 0 ? new ArgumentOutOfRangeException( locationName, $"{locationName} must be positive." ) : null;
}

public class OrderLine
{
    public OrderLine( int quantity )
    {
        this.Quantity = quantity;
    }

    // The property has a setter, which the aspect validates.
    [Positive]
    public int Quantity { get; private set; }
}

public static class Program
{
    public static void Main()
    {
        try
        {
            var line = new OrderLine( 0 );
            Console.WriteLine( line.Quantity );
        }
        catch ( ArgumentOutOfRangeException e )
        {
            Console.WriteLine( e.Message );
        }
    }
}
Quantity must be positive. (Parameter 'Quantity')

See Also

Reference

ILocationValidationAspect<T>
LocationLevelAspect

Other Resources

Creating Custom Contracts