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">
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>
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>
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>
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>
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>
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>
Saving File Layout in ReSharper
- In Visual Studio, navigate to
ReSharper
->Options
- Navigate to
Code Editing
->C#
->File Layout
- Click
XAML
in the top right corner - Copy and paste the above TypePattern into the XAML in the order you want it to fall (such as right before βDefault Patternβ)
- Click
Designer
in the top right corner to verify the new TypePattern displays correctly - Save your changes
Top comments (0)