When we built the undo/redo and threading models features of PostSharp 4.0, we needed had to address the problem of aspect dependencies. Both the Recordable and threading models aspects require the Aggregatable aspect. If the Aggregatable aspect is not present, it should be added automatically.

Checking whether an aspect has been added to a declaration

Adding a dependent aspect automatically is easy: it can be done with the IAspectProvider. What’s more difficult is to know whether an aspect has already been added to a declaration. The aspect can have been added as a custom attribute, as a multicast custom attribute, and in these cases the ReflectionSearch.GetCustomAttributesOnTarget method would do the job. But they also be added dynamically using through IAspectProvider, and up to now there was no API to reflect dynamically added aspects. That’s why we added the IAspectRepositoryService interface. It has two interesting features:

  • GetAspectInstances and HasAspect methods: Query aspects on a given declaration.
  • AspectDiscoveryCompleted event: Event raise after all aspects have been discovered and initialized.

To check whether an aspect has been added to a declaration, the following code is typically used in the implementation of IAspectProvider.

PostSharpEnvironment.CurrentProject.GetService<IAspectRepositoryService>.HasAspect( declaration, typeof(Aspect) )

Late validations

Sometimes it is necessary to programmatically validate code against the presence of aspects. This validation can be done only after all dynamic aspect providers (IAspectProvider) have been executed. For instance, child fields of an immutable class must have be themselves immutable or freezable, which means that, unless this is an intrinsically immutable type like int or string, the aspect must have the Immutable or Freezable aspect.

This is why we have the AspectDiscoveryCompleted event on the IAspectRepositoryService interface. It allows aspects to execute code at build time after all aspects have been discovered

Summary

Technically, the new service IAspectRepositoryService allows you to cope with complex dependencies between aspects. But more fundamentally, the feature allows you to create real language extensions composed of several aspects and custom attributes that play well together.

Happy PostSharping!

-gael

As we’re progressing in the RC cycle of PostSharp 4.0, I would like to shed some light on a feature that has been often requested in the past, and is finally available in PostSharp 4.0: OnInstanceConstructedAdvice.

The objective of this advice is to provide a way for the aspect to execute code when instances of the target class are “fully constructed”. What does that mean to be “fully constructed”? In short, it means that all instance constructors in the chain have been invoked. Note that it is not the same as having an OnSuccess advice on the public constructor: such advice would be executed even if the current constructor is not the last in the chain.

Example

Let’s see this on a simple example.Here’s an aspect that has both kinds of advices:

[PSerializable]
class MyAspect : InstanceLevelAspect
{
    private Type appliedTo;

    public override void CompileTimeInitialize(Type type, AspectInfo aspectInfo)
    {
        this.appliedTo = type;
    }

    [OnInstanceConstructedAdvice]
    public void OnInstanceConstructed()
    {
        Console.WriteLine("OnInstanceConstructed({0})", this.appliedTo);
    }

    [OnMethodSuccessAdvice, MulticastPointcut(MemberName = ".ctor")]
    public void OnSuccess(MethodExecutionArgs args)
    {
        Console.WriteLine("OnSuccess({0})", this.appliedTo);
    }
}

And here is some testing code:

[MyAspect]
class Foo
{
    public Foo()
    {
Console.WriteLine("Foo()"); } public Foo(int foo) : this() {
Console.WriteLine("Foo(int)"); } } static class Program { public static void Main() { Foo foo = new Foo(0); } }

The program is instantiating Foo by invoking a constructor that chains another constructor. Its output is the following:

Foo()
OnSuccess(ConsoleApplication7.Foo)
Foo(int)
OnSuccess(ConsoleApplication7.Foo)
OnInstanceConstructed(ConsoleApplication7.Foo)

As you can see, the OnSuccess advice has been invoked twice because two constructors were chained. However, OnInstanceConstructed was invoked only once after the last constructor completed.

Let’s have a more complex example:

[MyAspect]
class Bar : Foo
{
    public Bar() 
    {
Console.WriteLine("Bar()"); } public Bar(int bar) : this() {
Console.WriteLine("Bar(int)"); } } static class Program { public static void Main() { Bar bar = new Bar(0); } }

The output is the following:

Foo()
OnSuccess(ConsoleApplication7.Foo)
Bar()
OnSuccess(ConsoleApplication7.Bar)
Bar(int)
OnSuccess(ConsoleApplication7.Bar)
OnInstanceConstructed(ConsoleApplication7.Foo) OnInstanceConstructed(ConsoleApplication7.Bar)

As expected, OnSuccess is invoked twice. It may be more surprising to see OnInstanceConstructed invoked twice. The reason is that the method is actually called only once, but once for each instance of the aspect, and here we have two instances of MyAspect: one on Foo, and the other on Bar.

If you want to have a single execution of the logic, you have to make it conditional to this.appliedOnType:

[OnInstanceConstructedAdvice]
public void OnInstanceConstructed()
{
    if (this.appliedTo == this.Instance.GetType())
    {
        Console.WriteLine("OnInstanceConstructed({0})", this.appliedTo);
    }
}

How does it work?

The OnInstanceConstructed advice needs to “know” that the constructor is the last in the chain.

Let’s look at the code after it has been transformed by PostSharp:

internal class Bar : Foo
{
    public Bar() : this(ConstructorDepth.Zero)
    {
    }

    protected Bar(ConstructorDepth __depth) : base(__depth.Increment())
    {
        Console.WriteLine("Bar");
        this.<>z__aspect2.OnSuccess(null);
        if (__depth.IsZero)
        {
            this.OnInstanceConstructed();
        }
    }

    public Bar(int bar) : this(bar, ConstructorDepth.Zero)
    {
    }

    protected Bar(int bar, ConstructorDepth __depth) : this(__depth.Increment())
    {
        Console.WriteLine("Bar(int)");
        this.<>z__aspect2.OnSuccess(null);
        if (__depth.IsZero)
        {
            this.OnInstanceConstructed();
        }
    }

    protected override void OnInstanceConstructed()
    {
        base.OnInstanceConstructed();
        this.<>z__aspect2.OnInstanceConstructed();
    }
}

As you can see, PostSharp does three things with every user-defined constructor:

  • Add an argument of type ConstructorDepth to the original constructor.
  • Create a new constructor with the original constructor signature, which invokes the original constructor (with the modified signature) with the parameter ConstructorDepth.Zero.
  • In the constructor chain, add the argument __depth.Increment() to the original invocation.

Therefore, we know when the current constructor depth is zero and we’re able to invoke OnInstanceConstructed. If you’re looking at your code with System.Reflection, you will see that there are twice as many constructors. Naturally, you should invoke only the public or internal constructors, which have the original signature and initialize the depth to zero. Except reflection, the modification is harmless to user code.

Summary

The OnInstanceConstructed advice is the only reliable way to execute logic in the aspect only once after the instance has been fully constructed. We needed this feature to implement Aggregatable, Undo/Redo and Threading Models in PostSharp 4.0, and made it in a way that can be useful to everybody.

Happy PostSharping!

When we announced PostSharp 3.2 Preview, many of you shared your experience about the new features – especially threading models and undo/redo. We found it was such a significant release it would deserve a major version increase. So today, we’re proud to announce the availability of PostSharp 4.0 RC. There will be no PostSharp 3.2 release. PostSharp 3.2 has just been renumbered 4.0.

You can download PostSharp 4.0 RC from our web site. After you install the Visual Studio Extension, you can update your existing projects using NuGet Package Manager, by enabling the “pre-release” option.

What’s New in PostSharp 4.0?

Write thread-safe code in C# and VB using threading design patterns

Multithreading is difficult because we are reasoning about it at an absurdly low level of abstraction. Functional programming languages attempt to solve this problem by forcing you into a specific threading design pattern: Immutable Object. However, object-oriented programming is the right paradigm for most business applications.

PostSharp 4.0 brings the benefits of threading patterns to C# and VB. Instead of migrating your whole project to a different language, mark individual classes with one of the following custom attributes: [Actor], [Immutable], [Freezable], [Synchronized], [ReaderWriterSynchronized], [ThreadAffine] or (the anti-model) [ThreadUnsafe]. PostSharp will then ensure that your code is correct against the model, and will block you deterministically if this is not the case.

For more information, read Working with Threading Models in our documentation.

Implement Undo/Redo at model level

Undo/redo is one of the most-wanted features, but it is often absent from custom applications because it is so expensive to implement. There is no longer an excuse. The new [Recordable] aspect causes any change to your classes to be recorded, so they can be undone at any time. We provide ready-made buttons for WPF, but you can also build your own easily for Windows Phone or Windows 8.

For more information, read Implementing Undo/Redo in our documentation.

Aggregatable and Disposable Patterns

Aggregation – the parent/child relationship – is a fundamental concept of object-oriented design and a part of the original UML specification. Several design patterns rely on object aggregation. Despite its importance, the idea has not been implemented into programming languages, and is therefore the cause of much boilerplate code in most business applications.

For more information, read Implementing Parent/Child Relationships in our documentation.

Other enhancements in PostSharp Pattern Libraries

NofityPropertyChanged performance

We optimized performance of our famous NotifyPropertyChanged aspect. It is now 4 times faster at runtime.

Improved deadlock detection

The policy now also detects deadlocks involving synchronous calls to the WPF dispatcher.

Enhancements in PostSharp Aspect Framework

Dynamic Advices

In PostSharp 3.1, some advices were purely “static”. Either they were in the aspect, either they were not. In PostSharp 4.0, an aspect can take decisions dynamically about which advices must be added to the target class and members by implementing the IAdviceProvider interface. The interface allows to provide instances of one of the following advices: IntroduceInterface, ImportLocation, ImportMethod, IntroduceMethod.

Aspect Repository

It is now possible for an aspect to know which other aspects have been added to any declaration thanks to the IAspectRepositoryService. Plus, the AspectDiscoveryComplete event allows to run execute logic (typically for validation) after all aspects have been discovered.

Initialization Advices

OnInstanceConstructedAdvice lets you execute code after all constructors of a method have completed. We also added InitializeAspectInstanceAdvice, which extends RuntimeInitializeInstance with a parameter telling for which reason the aspect instance is being initialized.

Faster advice state lookup

Thanks to the DeclarationIdentifier property, it is easier to uniquely identify a member within a type. State can now be stored in an array instead of a dictionary, which makes lookups much faster. We use this feature to persist analysis results at build time and consume them at runtime.

Enhancements in PostSharp Core

Support for C++ assembly references

We solved issues where it was not generally possible to add aspects to a C#/VB assembly that referenced a C++ .NET assembly. The previous workaround (which was to use the managed host) is no longer necessary.

Support for WinRT and Windows Phone 8.1

We completely redesigned our support for .NETCore (the intimate name for .NET on Windows 8 and Windows Phone 8.1), and this is now much more reliable than before.

What did we drop in PostSharp 4.0?

Since we’re following the rules of semantic versioning, a new major release is an opportunity to abandon support for features that caused tension in our design and engineering processes. Therefore, we discontinued the following features:

  • Silverlight,  Windows Phone 7 and Windows Phone 7.5 are no longer supported by the PostSharp Model Pattern Library. The platforms are still supported by the core product itself (PostSharp.dll).
  • The IReaderWriterSynchronized interface has been fully deprecated.

PostSharp 3.1 will remain supported for a while and minor bugs will still be fixed. Issues that require important redesign will no longer be addressed in PostSharp 3.1.

Status of PostSharp 4.0 RC

We take the word release candidate seriously at PostSharp. The RC milestone means that the following criteria were fulfilled:

  • All planned features are implemented.
  • All new APIs have been reviewed and we predict no breaking change will be necessary, even with regard to other envisioned features.
  • All features have been tested internally.
  • A zero-defect point was reached at the time of release.
  • API documentation and tutorials are complete; testers did not report discrepancies or ambiguities in the documentation.

The ball is now in your camp; we need you to try to update your solutions (in a prototype branch) to the new version, run your test suite and report any issue. We will gather feedback during several weeks and promote the release to stable after community testing.

Summary

PostSharp 4.0 proposes a realistic approach to thread-safe object-oriented applications. We believe the significance of this innovation exceeds the scope of PostSharp and perhaps even .NET, since the concepts, if proven successful, could be implemented in other programming languages by a new generation of compilers. We’re obviously very proud of this achievement, and can’t wait to get feedback from the field.

Additionally, Windows and Windows Phone developers can now add undo/redo to their application with minimal effort thanks to our new Recordable pattern – a powerful alternative to the Memento pattern.

To realize these two new major features, we had to build new abilities in our aspect framework. You can now rely on these new types of advices to build automation for your own patterns.

We need your feedback to move this release to the stable milestone. Please download it from our web site and let us know what you think.

Happy PostSharping!

-gael