Open sandboxFocusImprove this doc

COM014: Collection Without Relationship Attribute in a Threading Model

Severity Warning
Reported by PostSharp.Patterns.Aggregation
Message Field/property <DeclaringType>.<Member> is a collection and must be annotated with the custom attribute [Child] or [Reference]. The member has been assumed to be a reference for backward compatibility.

Cause

The threading models, such as ThreadUnsafeAttribute or SynchronizedAttribute, add the AggregatableAttribute aspect to their target class, in a compatibility mode. When a field, or an automatic property, can hold either a child or a reference and has no relationship attribute, the [Aggregatable] aspect alone reports the error COM002. In this compatibility mode, PostSharp treats the member as a reference instead, and reports COM014 when the type of the member is a collection, because a collection has no good default.

In the following example, the items field of a [ThreadUnsafe] class is a List<string> without attribute.

using System;
using System.Collections.Generic;
using PostSharp.Patterns.Threading;

namespace Errors.COM014_Error;

[ThreadUnsafe]
public class ShoppingCart
{
    // The field is a collection, but it does not say whether it is a child or a reference.
    private readonly List<string> items = new List<string>();

    public void Add( string item ) => this.items.Add( item );

    public string Describe() => string.Join( ", ", this.items );
}

public static class Program
{
    public static void Main()
    {
        ShoppingCart cart = new ShoppingCart();
        cart.Add( "Keyboard" );
        cart.Add( "Mouse" );

        Console.WriteLine( $"Cart: {cart.Describe()}" );
    }
}
warning COM014: COM014_Error.cs(11,35): Field/property Errors.COM014_Error.ShoppingCart.items is a collection and must be annotated with the custom attribute [Child] or [Reference]. The member has been assumed to be a reference for backward compatibility.

Resolution

Annotate the member with one of the relationship attributes:

  • ReferenceAttribute when the class only refers to the collection or to its items. This keeps the behavior that PostSharp assumed.
  • ChildAttribute when the collection and its items belong to the class. A child collection must be an advisable collection, such as AdvisableCollection<T>.

In the following example, the list is a reference.

using System;
using System.Collections.Generic;
using PostSharp.Patterns.Model;
using PostSharp.Patterns.Threading;

namespace Errors.COM014_Fixed;

[ThreadUnsafe]
public class ShoppingCart
{
    // The list is a plain .NET collection, not a part of the object model: the cart only refers to it.
    [Reference]
    private readonly List<string> items = new List<string>();

    public void Add( string item ) => this.items.Add( item );

    public string Describe() => string.Join( ", ", this.items );
}

public static class Program
{
    public static void Main()
    {
        ShoppingCart cart = new ShoppingCart();
        cart.Add( "Keyboard" );
        cart.Add( "Mouse" );

        Console.WriteLine( $"Cart: {cart.Describe()}" );
    }
}
Cart: Keyboard, Mouse

See Also

Reference

ChildAttribute
ReferenceAttribute
ThreadUnsafeAttribute

Other Resources

Annotating an Object Model for Parent/Child Relationships (Aggregatable)
Working With Child Collections
Writing Thread-Safe Code with Threading Models