| Severity | Warning |
| Reported by | PostSharp.Patterns.Threading |
| Message | Attribute [<Attribute>] cannot be applied to "<Method>" because no threading model has been applied to the class "<Class>"; it will be ignored. |
Cause
The access level attributes, ReaderAttribute, WriterAttribute, UpgradeableReaderAttribute and YielderAttribute, do not add any code by themselves. The threading model of the class, for example ReaderWriterSynchronizedAttribute, reads them and acquires the lock that they specify when the method is called.
After PostSharp has discovered the aspects of the project, it reports THR041 for each method with an access level attribute whose declaring class has no threading model. The method then runs without any lock, which usually means that the threading model was forgotten. <Attribute> is the full name of the attribute type, for example PostSharp.Patterns.Threading.ReaderAttribute.
In the following example, the GetOrderCount method is annotated with [Reader], but the OrderHistory class has no threading model.
using System;
using PostSharp.Patterns.Threading;
namespace Errors.THR041_Error;
[ReaderWriterSynchronized]
public class ProductCatalog
{
private readonly decimal penPrice = 1.5m;
[Reader]
public decimal GetPenPrice() => this.penPrice;
}
// The class has no threading model, so nothing reads the [Reader] attribute of its method.
public class OrderHistory
{
private readonly int orderCount = 2;
[Reader]
public int GetOrderCount() => this.orderCount;
}
public static class Program
{
public static void Main()
{
Console.WriteLine( $"Price: {new ProductCatalog().GetPenPrice()}" );
Console.WriteLine( $"Orders: {new OrderHistory().GetOrderCount()}" );
}
}
warning THR041: THR041_Error.cs(21,16): Attribute [PostSharp.Patterns.Threading.ReaderAttribute] cannot be applied to "Errors.THR041_Error.OrderHistory.GetOrderCount" because no threading model has been applied to the class "Errors.THR041_Error.OrderHistory"; it will be ignored.
Resolution
- When the instances of the class are shared between threads, apply a threading model to the class, typically ReaderWriterSynchronizedAttribute.
- Otherwise, remove the access level attribute from the method.
In the following example, OrderHistory has the reader-writer-synchronized threading model, which acquires the read lock when GetOrderCount is called.
using System;
using PostSharp.Patterns.Threading;
namespace Errors.THR041_Fixed;
[ReaderWriterSynchronized]
public class ProductCatalog
{
private readonly decimal penPrice = 1.5m;
[Reader]
public decimal GetPenPrice() => this.penPrice;
}
// The threading model of the class takes the read lock when the method is called.
[ReaderWriterSynchronized]
public class OrderHistory
{
private readonly int orderCount = 2;
[Reader]
public int GetOrderCount() => this.orderCount;
}
public static class Program
{
public static void Main()
{
Console.WriteLine( $"Price: {new ProductCatalog().GetPenPrice()}" );
Console.WriteLine( $"Orders: {new OrderHistory().GetOrderCount()}" );
}
}
Price: 1.5
Orders: 2
See Also
Reference
AccessLevelAttribute
ReaderWriterSynchronizedAttribute
Other Resources