Disclaimer: I imported this post from WordPress to Jekyll on 9/2/23. Forgive the misformatting until I get a chance to clean it up.
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.
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:
Regions
In R# XAML, this is implemented by adding the RemoveRegions
flag in the TypePattern
node.
<TypePattern DisplayName="StyleCop Classes, Interfaces, & Structs" RemoveRegions="All">
Sort elements by type in the following order:
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>
Sort adjacent elements of the same type in the following order of access level:
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>
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>
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>
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>
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>
ReSharper
-> Options
Code Editing
-> C#
-> File Layout
XAML
in the top right cornerDesigner
in the top right corner to verify the new TypePattern displays correctly