As part of transitioning to a new API, I wanted a way to mark the old API as obsolete, so that Visual Studio (or ReSharper) would flag using of the old API as an error.
ObsoleteAttribute does exactly that – marks certain methods or types as obsolete, and has a constructor overload to specify whether the usage will be treated as an error or not. Unfortunately, in my case there was no source code for the old API (it was used as a 3rd-party DLL), and there’s no way to apply the Obsolete attribute to external DLLs without modifying the assembly using IL-rewriting tools.
It had occurred to me that perhaps this would be possible to achieve using one of ReSharper’s External Annotations, but there are no built-in annotations for this kind of task. The annotations mechanism is used to decorate various .NET types and methods with special attributes that provide ReSharper with additional information. Turns out, it is possible to use the same mechanism to apply the Obsolete attribute as well! This way, ReSharper could mark the usage as an error, even if it’s not really a compilation error (which is good enough for me!).
I previously wrote about how to add external annotations using XML files. According to ReSharper’s documentation, external annotation XMLs can be placed in one of the following locations:
[ReSharper install directory]\Bin\ExternalAnnotations\[Assembly name].xml
[ReSharper install directory]\Bin\ExternalAnnotations\[Assembly name]\[Any name].xml, where
[Assembly name]is the assembly name without the version
- Alongside the assembly, named
Since the old assembly was under my control, I chose the 3rd option, to place the annotations XML next to the assembly, and in the source control. This way, every team member that uses ReSharper will have this annotation enabled by simply updating to the latest source.
The external annotations XMLs are the same format as XML documentation files, generated by Visual Studio when you build your assembly. Supposing our assembly name is
Acme.OldServiceBusImpl.dll, and the type we want to make obsolete is called
EventBus, we need to create a file called
Acme.OldServiceBusImpl.ExternalAnnotations.xml, and place it beside the DLL. The file has the following content:
<assembly name="Acme.OldEventBusImpl"> <member name="T:Acme.OldEventBusImpl.EventBus"> <attribute ctor="M:System.ObsoleteAttribute.#ctor(System.String,System.Boolean)"> <argument>Use Acme.NewServiceBusImpl.ServiceBus instead.</argument> <argument>true</argument> </attribute> </member> </assembly>
This specifies that for an assembly named
Acme.OldServiceBusImpl, having a type
Acme.OldEventBusImpl.EventBus, add an attribute instance of
ObsoleteAttribute with the constructor overload
ObsoleteAttribute(string, bool), the boolean indicating the usage is considered an error.
After adding the XML file and reloading your project, ReSharper will now mark the usage of this type as an error! Your code will still compile, but you’ll get red on you!