Fixed pattern – C# 7.3 in Rider and ReSharper

The latest versions of ReSharper 2018.2 and Rider 2018.2 come with support for C# 7.3. In this series, we are looking at these new language features in C# 7.3. Today we will look at the fixed pattern and simplified access to fixed size buffer elements.

This post is part of a series:

Fixed statement

One of the common themes in C# 7.0 and the following point releases is to make it easier to write high-performance code. The feature we are going to cover today keeps this theme and is aimed to tackle the limitations of the fixed statement.

Let’s refresh our memory first and look at what the fixed statement does, and how to use it. Sometimes when interoperating with native code or when writing a performance-critical piece of code, we need to take a variable address and perform some operation on the pointer that stores the address. Because variables allocated on the managed heap can be moved during garbage collection, it’s required to fix them in order to use their addresses safely.

The fixed statement is intended exactly for this purpose, it “fixes” the movable variable so that its address remains constant for the duration of the statement. The example below demonstrates the use of the fixed statement:

Fixed pattern

Before C# 7.3, the fixed statement was able to work only with arrays, System.String, fixed-size buffers, or unmanaged variables. The knowledge of how to obtain the pointer to underlying data was hardcoded in the compiler.

This limitation makes using certain types (like Span<T>, ReadOnlySpan<T> or ImmutableArray<T>), which would naturally fit the fixed statement, either impossible, or unpleasant because of having to resort to the System.Runtime.CompilerServices.Unsafe API. Fortunately C# 7.3 extended the set of types valid for the fixed statement by introducing the fixed pattern.

Patterns are used in C# all over the place: the foreach statement, LINQ queries, await expression – all these language constructs rely on the shape of the type, i.e. their set of available instance or extension methods and properties. For example, if the type has a method GetEnumerator and its return type declares method MoveNext and property Current, then the type can be used in a foreach statement. Neither IEnumerable<T> nor IEnumerator<T> are demanded by the compiler.

In order for the type to implement the fixed pattern, it should declare a parameterless method GetPinnableReference that returns the value of the unmanaged type by reference (or read-only reference). The following code snippet shows and example of pattern-based fixed statement.

Note: read more about unmanaged types in our previous post about new C# 7.3 type constraints.

ReSharper and Rider come with a code inspection and quick-fix that allows to automatically generate the GetPinnableReference method from usage. Moreover, if the GetPinnableReference method already exists but its signature doesn’t match the expected one, another quick-fix is available to correct the method declaration.

Create 'GetPinnableReference' quick-fix

Simplified access to fixed size buffer elements

Let’s cover one more change introduced in C# 7.3: indexing fixed size buffer elements. Fixed size buffer fields are struct members available in unsafe contexts that represent C style in-line arrays. Such fields are rare beasts and primarily used for interoperation with native code. Let’s take a look at how they are declared.

Although the  field declaration above uses the same fixed keyword as in fixed statement, here it has a completely different meaning and expresses the constant length of the in-line array rather than constant address.

Before C# 7.3 accessing the elements of a fixed size buffer which can possibly reside in memory movable by GC was allowed only after pinning the buffer with the fixed statement, while fixed size buffers guaranteed to be located in non-movable memory could be indexed directly.

The requirement to introduce auxiliary fixed pointer declaration is unjustified for cases when fixed size buffer is only used to access its elements, because unless address of the buffer is stashed somewhere indexing is always safe.

Luckily C# 7.3 removed the unneeded limitation for indexing movable fixed size buffers and made their use more natural:

Sure enough, ReSharper and Rider detect places where the use of the fixed statement isn’t required and provide a convenient quick-fix to remove redundant fixed pointer declaration. Needless to say, that quick-fix can be applied globally in the current file, project, or our whole solution.

Remove redundant fixed pointer declaration quick-fix

It’s interesting to see C# not only evolve towards powerful abstractions and more expressive language constructs, but also towards supporting interoperability and writing high-performance code.

Download ReSharper 2018.2 now! Or give Rider 2018.2 a try. We’d love to hear your thoughts!

This entry was posted in How-To's and tagged , , , , , . Bookmark the permalink.

2 Responses to Fixed pattern – C# 7.3 in Rider and ReSharper

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #2652

  2. Pingback: Dew Drop - August 28, 2018 (#2791) - Morning Dew

Leave a Reply

Your email address will not be published. Required fields are marked *