DEV Community

loading...

Applying StyleCop Ordering with ReSharper File Layout

collinbarrett profile image Collin M. Barrett Originally published at collinmbarrett.com on ・7 min read

StyleCop with ReSharper

I have been wrestling a bit with the ideal ordering of members in my C# classes. Ordering members is obviously a cleanliness/maintainability factor and not a functional one, but I do want to create consistency in my classes.

As a heavy user of ReSharper (R#), I often apply their default C# File Layout via Code Cleanup to automatically re-arrange members. R#’s default File Layout is fairly good, but I would prefer to use Microsoft’s StyleCop ordering guidelines instead. R#, for example, does not default to ordering properties by access level, which I find valuable for consistency.

I found a handful of blog posts and resources around the web doing something similar, but none seemed to be recent and exactly compliant. Additionally, JetBrains does publish a StyleCop extension for R#, but its scope does not seem to be directly applicable to applying a File Layout alone.

StyleCop’s Ordering Rules

The StyleCopAnalyzer project has a subset of rules that I have converted for use in R# File Layout. This handful of rules were cherry-picked only in the sense that they meet the following requirements:

  • are applicable inside of a class, struct, or interface
  • are supported by R#’s File Layout feature
  • are not deprecated by StyleCop

SA1124: Do Not Use Regions

In R# XAML, this is implemented by adding the RemoveRegions flag in the TypePattern node.

<TypePattern DisplayName="StyleCop Classes, Interfaces, & Structs" RemoveRegions="All">
Enter fullscreen mode Exit fullscreen mode

SA1201: Elements Must Appear In The Correct Order

Sort elements by type in the following order:

  • Fields
  • Constructors
  • Finalizers (Destructors)
  • Delegates
  • Events
  • Enums
  • Interfaces
  • Properties
  • Indexers
  • Methods
  • Structs
  • Classes

In R# XAML, this is implemented by the order of Entry nodes. For example, to put fields before constructors:

<Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match></Entry><Entry DisplayName="Constructors"><Entry.Match><Kind Is="Constructor" /></Entry.Match></Entry>
Enter fullscreen mode Exit fullscreen mode

SA1202: Elements Must Be Ordered By Access

Sort adjacent elements of the same type in the following order of access level:

  • public
  • internal
  • protected internal
  • protected
  • private

In R# XAML, this is implemented via the Access node under Entry.SortBy like below for fields:

<Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /></Entry.SortBy></Entry>
Enter fullscreen mode Exit fullscreen mode

SA1203: Constants Must Appear Before Fields

In R# XAML, this is implemented by the order of the constant and field Entry nodes.

<Entry DisplayName="Constants"><Entry.Match><Kind Is="Constant" /></Entry.Match></Entry><Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match></Entry>
Enter fullscreen mode Exit fullscreen mode

SA1204: Static Elements Must Appear Before Instance Elements

In R# XAML, this is implemented via the Static node under Entry.SortBy like below for fields:

<Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /></Entry.SortBy></Entry>
Enter fullscreen mode Exit fullscreen mode

SA1214: Readonly Elements Must Appear Before Non-Readonly Elements

In R# XAML, this is implemented via the Readonly node under Entry.SortBy like below for fields:

<Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry>
Enter fullscreen mode Exit fullscreen mode

Final ReSharper File Layout XAML

Converting the above rules directly into ReSharper C# File Layout XAML results in the following TypePattern (also available as a Gist):

<TypePattern DisplayName="StyleCop Classes, Interfaces, & Structs" RemoveRegions="All"><TypePattern.Match><Or><Kind Is="Class" /><Kind Is="Struct" /><Kind Is="Interface" /></Or></TypePattern.Match><Entry DisplayName="Constants"><Entry.Match><Kind Is="Constant" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Fields"><Entry.Match><Kind Is="Field" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Constructors"><Entry.Match><Kind Is="Constructor" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Destructors"><Entry.Match><Kind Is="Destructor" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Delegates"><Entry.Match><Kind Is="Delegate" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Events"><Entry.Match><Kind Is="Event" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Enums"><Entry.Match><Kind Is="Enum" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Interfaces"><Entry.Match><Kind Is="Interface" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Properties"><Entry.Match><Kind Is="Property" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Indexers"><Entry.Match><Kind Is="Indexer" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Methods"><Entry.Match><Kind Is="Method" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Structs"><Entry.Match><Kind Is="Struct" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry><Entry DisplayName="Classes"><Entry.Match><Kind Is="Class" /></Entry.Match><Entry.SortBy><Access Order="Public Internal ProtectedInternal Protected Private" /><Static /><Readonly /></Entry.SortBy></Entry></TypePattern>
Enter fullscreen mode Exit fullscreen mode

Saving File Layout in ReSharper

  1. In Visual Studio, navigate to ReSharper -> Options
  2. Navigate to Code Editing -> C# -> File Layout
  3. Click XAML in the top right corner
  4. Copy and paste the above TypePattern into the XAML in the order you want it to fall (such as right before “Default Pattern”)
  5. Click Designer in the top right corner to verify the new TypePattern displays correctly
  6. Save your changes

StyleCop ReSharper File Layout TypePattern
StyleCop ReSharper File Layout TypePattern

Discussion (0)

pic
Editor guide