Trying to create a Region/Group with a file layout pattern
I am really new to ReSharper, but what I see so far, I really like. That said I am trying to figure out how to write a specific code cleanup rule. I have classes where I want to Generate code for Equality members (which works great), then I want to group those methods and operators together in a region and stick it at the bottom of the cs file as it needed, but not really part of my business logic.
I created a new rule/pattern (not sure of the correct term) that looks like this...

When I run "Cleanup Code", the only thing that gets put into the region is the overridden Equals method and the GetHashCode method. The implemented strongly typed Equals method and the == and != operators never get stuffed into the region. See sample class below.
What am I doing wrong?
Sample Class:
Snippet
using System;
namespace ReSharperTest
{
public class ModelA : IEquatable<ModelA>
{
public ModelA()
{
Counter = 0;
Name = string.Empty;
}
public ModelA(int counter, string name)
{
Counter = counter;
Name = name;
}
public int Counter { get; set; }
public string Name { get; set; }
public bool Equals(ModelA other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Counter == other.Counter && string.Equals(Name, other.Name);
}
public static bool operator ==(ModelA left, ModelA right)
{
return Equals(left, right);
}
public static bool operator !=(ModelA left, ModelA right)
{
return !Equals(left, right);
}
#region IEquatable Support
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((ModelA) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Counter * 397) ^ (Name != null ? Name.GetHashCode() : 0);
}
}
#endregion
}
}
Please sign in to leave a comment.
Hello Jim,
Are you able to share your "File Layout" code (XAML link at the right top corner of File Layout page in Options)?
Thanks!
Sure! Mind you, since posting this I have experimented many times trying to get this to work assuming that I am not understanding what I am doing, so what I am posting will not match the screenshot in the OP.
<?xml version="1.0" encoding="utf-16"?>
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
<TypePattern DisplayName="Non-reorderable types">
<TypePattern.Match>
<Or>
<And>
<Kind Is="Interface" />
<Or>
<HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
<HasAttribute Name="System.Runtime.InteropServices.ComImport" />
</Or>
</And>
<Kind Is="Struct" />
<HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" />
<HasAttribute Name="JetBrains.Annotations.NoReorder" />
</Or>
</TypePattern.Match>
</TypePattern>
<TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All">
<TypePattern.Match>
<And>
<Kind Is="Class" />
<HasMember>
<And>
<Kind Is="Method" />
<HasAttribute Name="Xunit.FactAttribute" Inherited="True" />
</And>
</HasMember>
</And>
</TypePattern.Match>
<Entry DisplayName="Setup/Teardown Methods">
<Entry.Match>
<Or>
<Kind Is="Constructor" />
<And>
<Kind Is="Method" />
<ImplementsInterface Name="System.IDisposable" />
</And>
</Or>
</Entry.Match>
<Entry.SortBy>
<Kind Order="Constructor" />
</Entry.SortBy>
</Entry>
<Entry DisplayName="All other members" />
<Entry DisplayName="Test Methods" Priority="100">
<Entry.Match>
<And>
<Kind Is="Method" />
<HasAttribute Name="Xunit.FactAttribute" />
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
</TypePattern>
<TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
<TypePattern.Match>
<And>
<Kind Is="Class" />
<HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
</And>
</TypePattern.Match>
<Entry DisplayName="Setup/Teardown Methods">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
<HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
<HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
<HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
</Or>
</And>
</Entry.Match>
</Entry>
<Entry DisplayName="All other members" />
<Entry DisplayName="Test Methods" Priority="100">
<Entry.Match>
<And>
<Kind Is="Method" />
<HasAttribute Name="NUnit.Framework.TestAttribute" />
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
</TypePattern>
<TypePattern DisplayName="Default Pattern">
<Entry DisplayName="Public Delegates" Priority="100">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Delegate" />
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Public Enums" Priority="100">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Enum" />
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Static Fields and Constants">
<Entry.Match>
<Or>
<Kind Is="Constant" />
<And>
<Kind Is="Field" />
<Static />
</And>
</Or>
</Entry.Match>
<Entry.SortBy>
<Kind Order="Constant Field" />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Fields">
<Entry.Match>
<And>
<Kind Is="Field" />
<Not>
<Static />
</Not>
</And>
</Entry.Match>
<Entry.SortBy>
<Readonly />
<Name />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Constructors">
<Entry.Match>
<Kind Is="Constructor" />
</Entry.Match>
<Entry.SortBy>
<Static />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Properties, Indexers">
<Entry.Match>
<Or>
<Kind Is="Property" />
<Kind Is="Indexer" />
</Or>
</Entry.Match>
</Entry>
<Entry DisplayName="Interface Implementations" Priority="100">
<Entry.Match>
<And>
<Kind Is="Member" />
<ImplementsInterface />
</And>
</Entry.Match>
<Entry.SortBy>
<ImplementsInterface Immediate="True" />
</Entry.SortBy>
</Entry>
<Entry DisplayName="All other members" />
<Region Name="IEquatable Support" Priority="100">
<Entry DisplayName="IEquatable" Priority="150">
<Entry.Match>
<Or>
<And>
<Access Is="Public" />
<Kind Is="Method" />
<Name Is="Equals" />
</And>
<And>
<Access Is="Public" />
<Override />
<Kind Is="Method" />
<Name Is="GetHashCode" />
</And>
</Or>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
<Entry DisplayName="Operators" Priority="150">
<Entry.Match>
<And>
<Access Is="Public" />
<Static />
<Kind Is="Operator" />
<Name Is="!=" />
</And>
</Entry.Match>
</Entry>
</Region>
<Entry DisplayName="Nested Types">
<Entry.Match>
<Kind Is="Type" />
</Entry.Match>
</Entry>
</TypePattern>
</Patterns>
Thanks for the File Layout.
As a fix, you might remove "<Name Is="!=" />" from "Operator" and when all operators will be placed into "IEquatable Support" region. I don't think "Name" property supports something like "!=" or "==" as a valid name.
Also you might opt for "All" item in "Remove Regions" combobox
Thanks!
OK, yes, that does move the != and == operators now, but
This is an explicit cast that I have contrived for this example. This code should not get moved as part of the new code arrangement as it doesn't have anything to do with IEquatable support.
public static explicit operator ModelA(int value)
{
return new ModelA {Counter = value};
}
Thanks for your suggestions though. Hopefully we can get this worked out!
Hello again!
After talking with an author of such feature in ReSharper, we found a solution to match != and == operators. You need to use compiler names for these operators:
The XAML view will be:
Hello Alexander!
Yup, that worked! Not exactly intuitive, but it worked!
Now, does your developer have any suggestions on getting the strongly typed Equals to be included? In the example above, it would be this one:
But, of course, the rule can't hard code "ModelA" as that is a generic method from "SnippetIEquatable<T>". That said, I'm not sure why that isn't just included under the the following snip (from my reply above)...
<Access Is="Public" />
<Kind Is="Method" />
<Name Is="Equals" />
Thanks!
Jim
Hello Jim,
Please try this
Hello Alexander,
Sorry, no difference for me. Is this working for you with my sample above? Or is this working for you with a different class?
Thanks,
Jim
Jim,
My apologies, forgot to mention one thing. Since strongly typed Equals method right now is covered by "Interface Implementations" pattern, so you need to add a rule to "Interface Implementations" not to include "Equals" name:
Then Equals won't be mapped by "Interface Implementations" pattern and will go to "IEquatable Support" region.
Thanks!
Fantastic! I also see that "Interface Implementations" is set to a Priority of 100/High and if I set mine to 150/Highest, it overrides "Interface Implementations" and I don't have to tweak "Interface Implementations".
I had set the line "<Entry DisplayName="IEquatable" Priority="150">" to 150/Highest, but that was inside "<Region Name="IEquatable Support" Priority="100">", so now I know that inner priorities don't override items in an outer scope.
One last question. One option with <ImplementsInterface /> is to say <ImplementsInterface Immediate="True" />. I can't seem to find any documentation to tell me what "Immediate" means or does.
Thanks for all your help with this,
Jim