Freezable Threading Model

When you need to prevent changes to an instance of an object most of the time, but not all of the time, the Immutable pattern (implemented by the ImmutableAttribute aspect) will be too aggressive for you. In these situations you need a pattern that allows you to define the point in time where immutability begins. To accomplish this you can make use of the FreezableAttribute aspect.

This topic contains the following sections:

To make an object freezable all you need to do is add the FreezableAttribute attribute to the class in question.

Making an object freezable using PostSharp Tools for Visual Studio
Note Note

This example shows freezing a class that only has primitive data types. Information on working with complex objects can be found the Freezable Object Trees section later in this article.

  1. First place the caret on the name of the object that you want to make freezable. The smart tag will appear below the object name. Expand it and select "Apply Threading Model...".

    Apply Threading Model Smart Tag
  2. In the Apply Threading Model wizard select "Apply freezable threading model" and click Next.

    Apply Freezable

    If you have not added a reference to the threading model assembly the Apply Threading Model wizard will download it from NuGet and add the reference.

  3. Once the wizard has completed the object will now be flagged as freezable and the Customer and Item properties have had Parent-Child relationships established on them.

    C#
    using PostSharp.Patterns.Threading;
    
    [Freezable]
    public class Invoice
    {
      public long Id { get; set; }
    }
Making an object freezable manually
Note Note

This example shows freezing a class that only has primitive data types. To see how to work with complex objects see the Freezable Threading Model section later in this article.

  1. Add the PostSharp.Patterns.Threading package to your project using NuGet.

  2. Add the FreezableAttribute custom attribute to your class.

    C#
    using PostSharp.Patterns.Threading;
    
    [Freezable]
    public class Invoice
    {
      public long Id { get; set; }
    }
Freezing an object

To freeze an object, use will first have to case the object to the IFreezable interface. After that you are able to call the Freeze() method.

C#
var invoice = new Invoice();
invoice.Id = 123456;

((IFreezable)invoice).Freeze();
Note Note

The IFreezable interface will be injected into the Invoice class after compilation. Tools that are not aware of PostSharp may incorrectly report that the Invoice class does not implement the IFreezable interface.

Instead of using the cast operator, you can also use the Cast<SourceType, TargetType>(SourceType) method. This method is faster and safer than the cast operator because it is verified and compiled by PostSharp at build time.

Note Note

If you are attempting to freeze either AdvisableCollection<T> or AdvisableDictionary<TKey, TValue> you will not be able to use the cast operator or the Cast<SourceType, TargetType>(SourceType) method. Instead, you will have to use the QueryInterface<T>(Object, Boolean) extension method.

Once you’ve called the Freeze() method on an object instance the code will no longer be able to change the property values on that instance. If a value change is attempted the code will throw an ObjectReadOnlyException.

C#
var invoice = new Invoice();
invoice.Id = 123456;

((IFreezable)invoice).Freeze();

// This will throw an exception.
invoice.Id = 345678;
Determining whether an object is in frozen state

To determine whether an object has been frozen, cast it to IThreadAware and get the readonly value from IsReadOnly via the ConcurrencyController property.

C#
var invoice = new Invoice();
invoice.Id = 123456;

((IFreezable)invoice).Freeze();

// The 'frozen' property will be set to 'true'.
bool frozen = ((IThreadAware)invoice).ConcurrencyController.IsReadOnly;
Freezable object trees

The Freezable pattern relies on the Aggregatable pattern. The AggregatableAttribute aspect will be implicitly added to the target class. Therefore, you can not only create freezable classes, but also freezable object trees. Read the Parent/Child Relationships for more information on how to establish object trees.

Important note Important

Children of freezable objects must be either freezable either immutable. Therefore, children classes must be annotated with the FreezableAttribute or ImmutableAttribute custom attribute. Collection types must be derived from AdvisableCollection<T> or AdvisableDictionary<TKey, TValue>.

See Also