There is some great static analysis stuff that ReSharper does for you. Specifically around nullability, purity and usage of your code. From their Code Annotations page in Visual Studio:

ReSharper Annotations help reduce false positive warnings, explicitly declare purity and nullability in your code, deal with implicit usages of member, support special semantics of APIs in ASP.NET and XAML frameworks and otherwise increase accuracy of ReSharper code inspections.

Right, what I said. This can be seen whenever you get shown a squiggle under a variable or statement telling you that an expression is always true, or when the signature IntelliSense shows you a [NotNull] annotation beside a parameter or return value.

NotNull Annotation Shown by Visual Studio help.

NotNull allows ReSharper to determine a condition is never false.

The obvious (and recommended) way is to take a dependency on jetbrains.annotations.dll. They have made this simple by making it a NuGet package. If you are adding annotations to your own applications, this is really easy. The problem if you are writing a library for public consumption you don’t want to be providing extra dependencies that the end user might not actually want or need. Also, if you don’t own the code, then you can’t change the source in the first place.

Luckily there is another way: *.ExternalAnnotations.xml.

Say you have a library that you distribute on NuGet. Your package can include a file beside your DLL that contains all the annotations that you would usually apply using attributes. When Visual Studio loads your DLL, ReSharper is able to recognise the XML file beside it, and load that into the system with all your custom annotation there to give a better experience.

Say you have a library DLL called Beefeater.dll. You would simply create a file called Beefeater.ExternalAnnotations.xml that gets packaged into your NuGet file, in the same folder as the DLL. The naming convention is simply *.ExternalAnnotations.xml where * matches the name of your library without the .dll extension. (Notice the not so subtle plug for my library Beefeater. More on that in another post.)

So what do we put in this file? Well it’s based on the XML Documentation format. You know, the one you use in your comments, that can be exported to produce documentation? If you didn’t know, watch out for more on that in a later post as well. All you really need to know is that it describes the signature of a method and allows you do define attributes against the method, or it’s parameters. Wherever you would put the attribute in code, you put it in that place in the file.

Let’s look at a specific example:


public struct NotNull<T>
{
    ...
    public NotNull(T value) : this()
    {
        ...
    }
}

public static class OptionExtensions
{
    ...
    public static void Match<TValue>(
      this Option<TValue> option, 
      Action<TValue> some, 
      Action none)
    {
        ...
    }
}
<assembly name="Beefeater">
    <member name="M:Beefeater.NotNull`1.#ctor(`0)">
        <parameter name="value">
            <attribute ctor="M:JetBrains.Annotations.NotNullAttribute.#ctor" />
        </parameter>
    </member>
    <member name="M:Beefeater.OptionExtensions.Match``1(Beefeater.Option{``0},System.Action{``0},System.Action)">
        <parameter name="some">
            <attribute ctor="M:JetBrains.Annotations.NotNullAttribute.#ctor" />
        </parameter>
        <parameter name="none">
            <attribute ctor="M:JetBrains.Annotations.NotNullAttribute.#ctor" />
        </parameter>
    </member>
    <member name="P:Beefeater.Result`2.Error">
        <attribute ctor="M:JetBrains.Annotations.NotNullAttribute.#ctor" />
    </member>
</assembly>

We have good examples of a few different features so I will step through them with a bit of an explanation for each. We start with the assembly, giving its name. Then we list many members inside this tag, one for each method we want to annotate.

To annotate a constructor, We use the M: prefix, to define that this is for a method. We add the full namespace to the type, in this case, our class is Beefeater.NotNull<T>. Our type is generic, so we use the `1 syntax to declare that the type has a single generic type parameter. If we had 2 parameters we would have used `2. Because it is a constructor, we use the #ctor to represent its name. Our constructor takes one parameter, and it is of type T from the generic, so we use `0 to declare the first (zero-based indexing, of course) of the generic types.

Next we have a nested parameter tag. This one declares the name of the parameter and contains any attributes applied to that parameter. The attribute has a ctor attribute where we put the fully qualified name of the constructor we use on that attribute. This is a repeat of the above syntax described for the member name.

Our second method has a few extra bits of information to know. Firstly, we are using the name .Match``1 which is the actually method name since it isn’t a constructor, and is generic since the method is generic, like the class was last time. Secondly, with parameters that are known types, we use their fully qualified name. We see the last parameter is a System.Action. The other two are generic types. This took me a while to figure out, but if your method is generic, your parameters are generic, and you need to match these together, you use the {``0} syntax, to say it has a generic argument, of type `0, where `0 matches the first argument of the generics from the method (or class).

The last method shows an attribute on the member. This uses the same attribute tag and works the same way as the other attribute tags previous. We just nest it directly under the member, instead of inside a parameter tag.

It was helpful to refer to Processing the XML File on MSDN to get a feel for what the type and method signatures look like.

For a list of all the attributes you can use, check out the ReSharper Reference on Code Annotation Attributes for a full detailed reference, or the ReSharper features page for a more marketing driven overview description and list of the most significant of the attributes available.

A more detailed article (without the generic help though) can be found on JetBrains help, which is what got me off the ground with most of what I needed to do.

I mentioned there are three ways to use ReSharper static analysis. So what it the third? Well, You can write your own attribute classes, and tell ReSharper about them. You need access to the source code to use this approach as well, but it does remove a dependency on ReSharper specifically. I’ll leave it to you to decide if this makes sense over the preferred approach of using the DLL provided.