We're happy to announce the release of PostSharp 6.5 RC, available for download on our website.

Most of our efforts with PostSharp 6.5 went into improving the build-time and design-time experience of PostSharp. We also now proudly and officially support Docker, after we have successfully tested our product with all Docker images of .NET Core provided by Microsoft.

This release contains the following improvements:

  • Performance enhancements
  • Installer improvements
  • Docker support
  • Platform updates


Performance enhancements

The startup time of PostSharp on .NET Core has decreased significantly.

The decrease is from 1,100 ms to 400 ms. That is a 2.5 times improvement. Building a lot of small projects should now be significantly faster. To achieve this improvement, we generate ReadyToRun images of PostSharp on the fly on each build machine. This feature can be disabled by setting the PostSharpReadyToRunDisabled MSBuild property to True.

Therefore we are glad to announce that PostSharp performance on .NET Core is now on a par with the one on .NET Framework!


Emitting errors and warnings is now significantly faster.

We removed an overhead of approximately another 400 ms on the first message and further improved the time to emit subsequent messages. The expensive part of emitting a message was to determine in which file and on which line the message should be anchored, and this is what we worked on.

Previously, on the first message, PostSharp loaded Roslyn to parse the source file and tried to locate the line and column of the offending code element. Loading Roslyn was a significant one-time overhead unless native images were present, and even then the cost of parsing was linear to the number of offending files - which could grow high if there was a lot of warnings. Now, we are using a Roslyn analyzer to export the location of all code elements (you will find a new pspdb file in your output directory). This analyzer resides in the Roslyn process itself and uses the already-parsed Roslyn code model, therefore it is very fast. This approach also allows us to find the source code of types with no method body at all, such as interfaces or enums, which previously we were not able to do. The new strategy causes a performance loss when there is no warning at all, but usage data shows that only a minority of projects would be negatively affected.

The analyzer can be disabled by setting the PostSharpRoslynAnalyzerDisabled property to True, but in this case errors and warnings will not be resolved to a source code location.


PostSharp Tools for Visual Studio is now even smoother.

PostSharp tools for VS is significantly better, since we continued to apply the async pattern everywhere. We also optimized memory usage so you should get a better experience with large solutions.


Installer improvements

The installer now lets you:

  • choose which instances of Visual Studio PostSharp should be installed into,
  • kill blocking processes, and
  • easily see the installation log in case of failure of VsixInstaller.exe. 


Docker support

We've tested PostSharp on Docker thoroughly and fixed a few issues with thin Windows images.


Platform updates

  • We added support for the modern Microsoft.Extensions.Caching.Memory.IMemoryCache interface of .NET Core and Microsoft.Azure.ServiceBus, the new API for Azure Service Bus.
  • Visual Studio 2017 RTM (15.0) is no longer supported. It is replaced by Visual Studio 2017 Update 1 (15.9, LTS).




In PostSharp 6.5 we focused on two areas: improving the build-time and design-time experience of PostSharp. 

We are happy to say that, in line with our previous announcements about support for .NET Core, PostSharp performance on .NET Core is now on a par with the one on .NET Framework.

As always, it is a good time to update your VS extension and NuGet packages, and report any problem via our support forum


Happy PostSharping!

I created and published my first Android app: an initiative tracker for pen-and-paper roleplaying games. If you have an Android tablet, you can download it off Google Play and try it out. As opposed to my earlier attempts, I now used Xamarin with XAML and PostSharp (the product we make). In this article, I walk through my experiences.

Soothsilver Initiative Tracker

The app looks like this:

In pen-and-paper roleplaying games, such as Dungeons & Dragons, in combat, players take turns in the order of initiative: a number based on what each player rolls on a die. Because each player takes several turns in a combat, and the order of players is different each combat, playgroups make use of an initiative tracker to keep track of whose turn it is, who goes next and so on.

As you might expect, there are many initiative trackers on Google Play already. I know because I tried them all — but not one that matched all of my requirements exactly, so, of course, I rolled out my own :).

And it worked well — I made it within half a day (though the subsequent process of publishing it on Google Play took about as many hours again) — and our playgroup is still using it four months later.

I should mention that is entirely my own personal hobby project — I host in on my own GitHub (give me a star) and PostSharp as a company certainly does not provide support (but feel free to ask me). We don't even officially support Android at the moment, though as evidenced by this app, it generally works, including debugging.

Using Xamarin with XAML

I made some attempts at Android development before, using Java/Kotlin and native Android API, but I often got stuck and never created anything worth publishing. That's why this time I tried if maybe using C#/.NET would work better.

It did, curiously, but it still wasn't close to desktop development. You know how when you're developing a desktop application and you type in some code and press F5 and it immediately just runs? And how when you're developing a mobile application and you need to install several prerequisites and check manifests and set configuration options? That's still there, even when you're using Xamarin.

There's also the fact that everything is slower: the designer, the build, the transfer to your device or to the emulator, even the distribution process and upload to Google Play. I think if I had more experience, it would go faster, but I still found the entire process more complicated. Part of the reason why I don't create mobile games.

The user interface design, at least, was more familiar. I used Xamarin Forms with XAML design files and the paradigm is very similar to UWP and WPF so I created my screens quickly. Visual Studio now even supports live updates: I modified my XAML, saved the file, and the form on my device changed!

Of course, XAML also means INotifyPropertyChanged, the XAML solution to data binding.


I've used INotifyPropertyChanged in several projects so far and I still don't quite like it.

Personally, as far as binding values to user interface elements goes, my number one favorite approach is the low-level draw loop (as in XNA/MonoGame): you ask your model sixty times a second what are you supposed to draw and you draw that. That isn't an option in complex UI frameworks.

My next favorite approach is the one taken by JavaFX: you use special smart properties (wrappers) in your model and bind them among themselves. I find that clearer, less boilerplatey, but it's getting complex, especially with the larger elements like list views.

Regardless, Xamarin has XAML, and XAML means MVVM and INotifyPropertyChanged. Fortunately, this time, I have PostSharp.

PostSharp auto-implements everything about INotifyPropertyChanged. With it, I was able to reduce the interacting part of my model to this:

public class Creature : INotifyPropertyChanged
  public string Name { get; [ThenSave] set; }
  public bool Friendly { get; set; }
  public int Initiative { get; set; }

  public bool Active
    get { return MainPage.Instance.Encounter.ActiveCreature == this; }

  public Xamarin.Forms.Color BackgroundColor
      if (Friendly) { return Color.PaleGreen; } else { return Color.LightSalmon; }

PostSharp's solution to INotifyPropertyChanges is magic so I'll walk you through what's happening here.

The [NotifyPropertyChanged] attribute is a PostSharp attribute and it means "whenever any property of this class changes, raise a PropertyChanged event for that property". For the properties Name, Friendly and Initiative, it means the event is raised after some code uses their setter.

But what about the properties Active and BackgroundColor which are getter-only?

The property MainPage.Instance.Encounter.ActiveCreature is referenced via a static property (MainPage.Instance) so there's no way to react to its change from within the class Creature. What I do in this app is that I use OnPropertyChanged to manually raise the PropertyChanged event for the property Active for all creatures whenever the active creature changes. PostSharp can't help here because of the unfortunate way in which I set this up. What I should have done instead is add to the Creature class a reference to its parent Encounter, which removes the need to refer to a static property.

For BackgroundColor, the situation is different. The property's value depends only on another property of the same creature: whether it's friendly or not. PostSharp can determine this (it reads the IL code of BackgroundColor's getter and sees that it references the property Friendly) and makes it so that whenever the value of Friendly changes, a PropertyChanged event is raised also for BackgroundColor — and I didn't need to write any code.

The [SafeForDependencyAnalysis] attribute in my code sample is a signal to PostSharp that even though the code within uses static properties, it's okay and PostSharp shouldn't emit a warning. PostSharp normally emits the warning to tell the user "hey, I can't automatically raise events in response to changes of static properties; are you sure you're handling that yourself?". It's necessary even for BackgroundColor because it refers to Color.PaleGreen and Color.LightSalmon, and those aren't constants, they're merely static fields. (They are readonly, so maybe the warning isn't really necessary and we could look into suppressing it.)

Other uses of PostSharp

You may have noticed a couple of extra attributes in my code sample.

Those weren't strictly necessary but since I was using PostSharp already, I figured, why not go all the way.

[ThenSave] is a method boundary aspect I created. It means, "after this method completes, save all creatures on disk so they're not lost when the user closes the app". I could have done this instead:

private string _name;
public string Name { get => _name; set { _name = value; ThenSave.SaveEverything(); } }

Which would do the same thing, but I feel like the solution with the [ThenSave] aspect is prettier and if I needed it for more than one property, it would also help save lines of code.

The last attribute I didn't talk about is [Recordable]. This one is a built-in PostSharp attribute which means "I remember everything that happens to me; you can use undo/redo."

Normally, when you implement undo/redo, for each possible action the user can take, you create a triplet: what happens when you take the action, what happens when you undo it, and what happens when you redo it.

PostSharp's undo/redo makes use of the fact that most of the time, everything that these actions do is just changing the values of some properties. So, whenever you change the value of some properties of a [Recordable] object, the object remembers it and it's added to the undo stack which I exposed with the Undo and Redo button on screen.

I also marked the list of all creatures (the class Encounter) as [Recordable] as well. That way, if I first change the name of one creature in the encounter and then another, both changes are made to the same undo stack and can be undone in turn by the same button.

I suppose the app didn't really need an undo/redo functionality. Most initiative trackers on Google Play don't have one. But with PostSharp, it cost me very little to add it and it actually proved useful, especially since typing is more time-consuming on tablets so undoing a mistaken name change rather than retyping the original name helps speed up gameplay.

Publishing on Google Play

I didn't technically need to publish the game: I mostly wanted it for myself and the build that Visual Studio placed on my tablet was good enough. But publishing seemed simple enough and maybe in the future I'll want to create a true game and this could be a trial run.

It wasn't actually all that simple. The Google Play Console, the online app that you use to upload and manage your Google Play games, has about twenty pages that you can fill in and about half of them are mandatory.

Uploading the binary itself failed several times for me when I checked the wrong checkboxes when creating the distribution build in Visual Studio. Visual Studio has a feature that allows you to upload your build to the Play Console from Visual Studio, but it broke at some point in the past and doesn't seem to work anymore. Still, for every problem I faced, there was a forum thread somewhere on the internet that pointed me in the right direction.

The cost of creating a Google developer account was just $25 and it's a one-time fee that I don't need to pay for future apps.

Whenever I made a change to the game data, either uploading a new build or even fixing a typo in the store listing description, it required a new verification from Google, which seems to be manual at least the first time around: it took about a week to get my first version approved (but subsequent approvals were faster). I didn't actually talk or chat with a human at any point.

Overall, it was a good experience, though I recommend that you do this on a powerful computer (because creating the distribution build is slow) and with good internet (because the distribution package for Google Play is large and you need to upload it).


I'm happy with how my app turned out.

I used the free Essentials edition of PostSharp (more than enough for a little app like this). As an employee, I had access to the full Ultimate edition but I didn't need it. (You may also be eligible for a free Ultimate license.)

If I didn't use PostSharp, I certainly wouldn't have implemented Undo/Redo and my Encounter and Creature classes would increase in size and complexity a bit but with a bit of refactoring, it would still be quite manageable, I think. That said, XAML is a technology where PostSharp shines and I certainly prefer the current code than what it would have been without PostSharp.

C# 8.0 introduces nullable reference types. These are yet another way to specify that a given parameter, variable or return value can be null or not. But, unlike attribute libraries such as JetBrains.Annotations, Microsoft Code Contracts or PostSharp Contracts, nullable reference types have built-in compiler support and so we can hope for a much wider adoption.

In PostSharp 6.4, we added full support for C# 8.0 and that includes nullable reference types. In this article, I discuss what we needed to do to implement this feature.

PostSharp as a code weaver

PostSharp is primarily a code weaver: it modifies the assembly produced by the C# compiler. As such, it works on your own code, and you may already be using nullable reference types. Did PostSharp need to do anything to keep working well in such scenarios?

It turns out that no, not really. Everything just works. Of course, C# doesn't have an up-to-date specification anymore, so it's hard to say for certain. But based on our tests and the information we collected from the web (especially the nullable-metadata.md file and the description of the new nullable-related attributes), PostSharp would continue working fine even had we done nothing. And we did a lot of testing, in fact, most of the time I spent implementing C# 8.0 support was spent on manual and automated testing.

The reason everything sort-of just works is that at the IL level, at which PostSharp operates, nullability annotations are represented as hidden attributes.

The hidden nullability attributes of C# 8

When you type string? myField in C#, compile it and then decompile with a pre-C# 8 decompiler, you will get [System.Runtime.CompilerServices.NullableAttribute(2)] string myField;. The NullableAttribute is one of two new "hidden" attributes. Its parameter determines the nullable state of the type:

  • 0 means null-oblivious (pre-C# 8 or outside a nullable annotation context),
  • 1 means non-nullable (e.g. "string"), and
  • 2 means "may be null" (e.g. "string?").

The use of attributes in this way means that old code created before C# 8 can use C# 8 code. For us, it also meant a lot less work. After all, PostSharp is all about attributes so we're well equipped to handle those.

That said, there were a couple of corner cases that we wanted to solve. They may seem a little convoluted. Certainly most of our users will never encounter them. But they existed and we never want to ship a product with known defects. We've been burned by that before when it forced us to make backwards-incompatible changes later to fix the defects.

So here's one such edge case:

Edge case 1: Nullability of methods introduced with [IntroduceMember]

PostSharp has an attribute called [IntroduceMember] which you can use to insert a property or a method into another class, like this:

public class Creature
  public string? Description { get; set; }
  public int? MaximumAge { get; set; }
public class SelfDescribingAttribute : InstanceLevelAspect
  public string ImportedDescription;
  public string DescribeSelf()
      return "I am " + ImportedDescription;

In the example above, the SelfDescribingAttribute adds the method DescribeSelf to the target class Creature.

Now, PostSharp modifies the binary, not the source code, so you won't actually be able to use the method in this project or in projects in the same solution (because project references refer to source code, not the binary). That is why this feature is used mostly to add methods expected by frameworks (the most notable case being XAML/PropertyChanged).

However, if somebody else imports your projects as a DLL library (either by referencing the .dll file itself, or as a NuGet package), they will see the introduced method. From their perspective, the class would look like this:

public class Creature
  public string? Description { get; set; }
  public int? MaximumAge { get; set; }
  public string DescribeSelf();

But what then is the nullability of the return type of the method DescribeSelf — is it non-nullable (string) or nullable (string?). By the principle of least surprise, we felt the correct answer is "the same as in the template method", which here means non-nullable, so that's what we do — we make sure the metadata on the introduced member reflects that.

But if we did nothing (by not copying any attributes from the template method onto the target method), then in this case, the answer would be nullable. Why? Because the C# compiler doesn't just use NullableAttribute to mark which values are nullable, it also saves up on the assembly size by compacting several NullableAttributes into a single NullableContextAttribute.

The exact algorithm is described in the nullable-metadata.md file but it's along the lines of "if a class has more nullable members than non-nullable members, annotate only the non-nullable members with NullableAttribute and mark the class itself as nullable using NullableContextAttribute". The class would look like this: 

[Nullable(0)] // Class itself doesn’t have a nullability
[NullableContext(2)] // Members are nullable.
public class Creature
  public string Description { get; set; } // Inherits nullability from class
  public int MaximumAge { get; set; } // Inherits nullability from class
  public string DescribeSelf(); // Oops, this was supposed to be non-nullable.

Now you may already see the problem. The target class was considered entirely nullable, but now we're introducing a method with a non-nullable return type to it. Therefore, we must take care to copy (or create, if necessary) proper attributes on any introduced methods (and the methods' parameters and return values) and on any introduced properties and events.

That's why the final class, as modified by PostSharp, would look like this if decompiled:

public class Creature
  public string Description { get; set; }
  public int MaximumAge { get; set; }
  [NullableContext(1)] // The method’s return value and any parameters are non-nullable
  public string DescribeSelf();

Edge case 2: New attributes on fields

Let's move to another edge case, one that occurs when you add one of the new nullability custom attributes (AllowNull, DisallowNull, MaybeNull, …) to a field or property.

These attributes allow you to express the nullability semantics of properties and methods that are more complex than "always may be null" or "is never null". For example, you may put the new [AllowNull] attribute on a property which is otherwise non-nullable. That is a note to the compiler that "null is allowed to be put into this property, but, since this is a non-nullable property, it will never return null".

Here's how you might use such an attribute:

[AllowNull, // <- a C# 8 attribute
UseRandomNameIfNull] // <- an example LocationInterceptionAspect, explained further down
public string Name { get; set; }

The AllowNullAttribute combined with the fact that the property type (string) is non-nullable in C# 8, means that this property's nullable status can be explained in English like this: "I never return null, but feel free to assign null to me. I'll handle it."

In vanilla C#, you could handle it by implementing the property's getter to return something instead of null, or by implementing its setter to assign something to a backing field. With PostSharp, you can do the same thing with a LocationInterceptionAspect:

public class UseRandomNameIfNullAttribute : LocationInterceptionAspect
  private string name;
  public override void OnGetValue(LocationInterceptionArgs args) 
    if (args.Value == null) {
      if (name == null) {
        name = R.GenerateRandomString();
      args.Value = name;

But with PostSharp, you can also apply location interception aspects to fields, like this:

[AllowNull, UseRandomNameIfNull]
public string Name;

When I did that while testing PostSharp with C# 8, everything seemed fine — until I loaded the PostSharp-modified assembly in another project, at which point Visual Studio started complaining that I'm assigning a null to a non-nullable property. But why? Did I not use the AllowNull attribute properly?

Well, the way PostSharp makes location interception aspects work for fields is by transforming them into auto-implemented properties. That means that the IL code, decompiled, would look more like this:

[AllowNull, UseRandomNameIfNull]
public string Name { get; set; }

That seems just like the previous declaration, which works without a hitch. The problem is that the C# 8 compiler, when it sees [AllowNull] or [DisallowNull] on a property, silently moves those attributes to the property setter's parameter (the keyword "value"). A similar thing happens for [MaybeNull] and [NotNull]: those attributes get moved by the C# compiler onto the getter's return value.

This was a surprise to me. There being no specification, I looked in GitHub history but found little. I do remember that I found a single comment about this on some related issue (I lost it) and I know that this wasn't yet decided in May 2019, but that's it. Either way, emulating Roslyn helped, so PostSharp now does what the C# compiler does and moves these attributes onto their appropriate places if you declare them on a field.


As you can see, implementing support for C# 8.0 was not completely obvious, but we managed to address the corner cases anyway. But wow, do I miss the days that C# had a complete specification :). I completely empathize with the commenter at issue 64.

And there's still work to be done. PostSharp is not only a code weaver, but also a collection of libraries (such as PostSharp Logging or PostSharp Caching). As a library producer, we will eventually want to annotate our public API with question marks and the new attributes. I'm actually looking forward to this: going through all public types and methods and investigating their nullability sounds fun. Until then, even though our API remains null-oblivious, our code weaver handles code with nullable reference types well.