I have my own custom profile for Organise Members, but I'm struggling with one aspect of it. One style rule we have is that if a class has any other classes defined within it, then these should be declared above the parent class's methods. To facilitate this I've got two entries at the end of my profile, below the items I want explicitly placed above them (eg, fields, event declarations, etc). The first is a group by with "Kind" set to "Class". There is no sort on it, so that the class order remains as it was manually configured. Below that I have another group by, this time with "Kind" set to "Member". The intention was that the last two groups in my source file would be any child classes, followed by any members , however the child classes get moved to the bottom. Sort of
I have a test class I'm playing with as I write this, and I think I've just narrowed down the behaviour. My child classes are always in a region block. If I have a single class in a region above my methods, it remains there. If I add a second class to the region then the region containing the two classes is moved to the bottom of the source file. If I put each class in its own region then they both remain at the top of the file. This only seems to be an issue in a VB project, in C# it works fine
Here's a simple class that exhibits the problem:
Visual BasicPublic Class Atest
#Region "test"
Class one
Property Test As String
End Class
Class two
Property Test As String
End Class
#End Region
Public Sub New()
End Sub
End Class
Running organise members on this should leave it untouched, but instead it moves the region below the constructor. Remove the region declarations and it behaves correctly. Remove one of the child classes and it behaves correctly.
I've attached my settings that include the rules
Hi Kevin,
Thank you for providing the code sample and CodeRush settings. I have reproduced this behavior and it relates to the current logic of the Organize Members feature. If a few members are wrapped into the region directives, they are excluded from organization and added at the end of a type.
> This only seems to be an issue in a VB project, in C# it works fine
On my side the behavior for both languages is identical. Please provide us with the C# code sample with different behavior?
> My child classes are always in a region block.
If I understood you correctly, this region block always has the same name. In this case, I recommend you wrap the "Child Classes" rule in the region with the required name. Then, child classes will not be excluded from organization and a region block will be saved. To wrap the rule in the region, perform the following steps:
Let us know whether this suggestion suits you.
Hi Alexander,
Below is a C# example that behaves correctly, despite having multiple classes in the region block:
namespace Saturn.Core.Tests { class Class1 { #region Test class one { public string Test { get; set; } } class two { public string Test { get; set; } } #endregion public Class1() { } void SomeMethod() { } } }
Here is a screencast that illustrates it working correctly on my PC
I'll follow up in a second on the workaround - I just tried it quickly and something strange seemed to happen
Here is the code I just tested the workaround on:
Imports Saturn.ViewInterfaces.Admin Namespace Admin Public Class EdiLogViewController Inherits PeelPorts.DependencyInjection.Controllers.SingleInstanceController Private WithEvents _view As IEdiLogView Private _context As Business.Context.ISaturnContext #Region " Summary Classes " Public Class GateLog Implements IEdiLogView.IGateLog Public Property AcceptedTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.AcceptedTime Public Property Booking As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Booking Public Property Container As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Container Public Property Direction As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Direction Public Property EmptyLaden As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.EmptyLaden Public Property Equipment As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Equipment Public Property EventTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.EventTime Public Property MatchedGate As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.MatchedGate Public Property Message As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Message Public Property ReceivedTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.ReceivedTime Public Property Sender As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Sender Public Property Succeeded As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Succeeded End Class Public Class LoadDischargeLog Implements IEdiLogView.ILoadDischargeLog Public Property Booking As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Booking Public Property Container As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Container Public Property Direction As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Direction Public Property EmptyLaden As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.EmptyLaden Public Property Equipment As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Equipment Public Property EventTime As Date Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.EventTime Public Property Sailing As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Sailing Public Property Sender As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Sender Public Property Vessel As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Vessel End Class #End Region Public Sub New(ByVal context As Business.Context.ISaturnContext, ByVal view As IEdiLogView) MyBase.New(context), view) _view = view _context = context End Sub Public Overrides Sub Run() MyBase.Run() End Sub Private Sub FetchGateMoves(ByVal startDate As Date, ByVal endDate As Date) endDate = endDate.AddDays(1) _view.GateData = (From item In _context.Logs.Codeco.SetMergeOption(Data.Entity.Core.Objects.MergeOption.OverwriteChanges) Where item.EventTime > startDate And item.EventTime < endDate Order By item.EventTime Select New GateLog With { .AcceptedTime = If(item.RetrySucceeded, item.Logged), .ReceivedTime = item.Logged, .EventTime = item.EventTime, .Booking = item.Booking, .Container = item.Container, .Direction = item.Direction, .EmptyLaden = If(item.IsEmpty, "Empty", "Laden"), .Equipment = item.Equipment, .MatchedGate = item.Location.Name, .Message = item.Message, .Sender = item.Sender, .Succeeded = If(item.Succeeded, "Succeeded", "Failed")}).ToList End Sub Private Sub FetchLoadDischargeMoves(ByVal startDate As Date, ByVal endDate As Date) endDate = endDate.AddDays(1) _view.LoadDischargeData = (From item In _context.Logs.Coarri.SetMergeOption(Data.Entity.Core.Objects.MergeOption.OverwriteChanges) Where item.EventTime > startDate And item.EventTime < endDate Order By item.EventTime Select New LoadDischargeLog With {.EventTime = item.EventTime, .Booking = item.BookingRef, .Container = item.Container, .Sender = item.Sender, .Direction = If(item.IsLoad, "Load", "Discharge"), .EmptyLaden = If(item.IsEmpty, "Empty", "Laden"), .Equipment = item.Equipment, .Sailing = item.SailingRef, .Vessel = item.Vessel}).ToList End Sub Protected Overrides Sub OnSubmitChanges() Throw New InvalidOperationException End Sub Private Sub _view_FetchData(ByVal sender As ViewInterfaces.Admin.IEdiLogView, ByVal type As ViewInterfaces.Admin.IEdiLogView.LogType, ByVal startDate As Date, ByVal endDate As Date) Handles _view.FetchData If type = IEdiLogView.LogType.Gate Then FetchGateMoves(startDate, endDate) Else FetchLoadDischargeMoves(startDate, endDate) End If End Sub Private Sub _view_Drilldown(sender As Object, container As String, reference As String) Handles _view.Drilldown If String.IsNullOrWhiteSpace(container) = False Then Drilldown.ToContainer(container) End If If String.IsNullOrWhiteSpace(reference) = False Then If Text.RegularExpressions.Regex.Match(reference, Core.RegularExpression.BookingReference).Success Then Drilldown.ToShippingJob(reference) ElseIf Text.RegularExpressions.Regex.Match(reference, Core.RegularExpression.ItineraryReference).Success Then Drilldown.ToItinerary(New DBKey(reference), Nothing) End If End If End Sub End Class End Namespace
and this is the result of running organise members:
Imports Saturn.ViewInterfaces.Admin Namespace Admin #Region "Summary Classes" Public Class EdiLogViewController Inherits PeelPorts.DependencyInjection.Controllers.SingleInstanceController Private _context As Business.Context.ISaturnContext Private WithEvents _view As IEdiLogView Public Sub New(ByVal context As Business.Context.ISaturnContext, ByVal view As IEdiLogView) MyBase.New(context, view) _view = view _context = context End Sub Public Overrides Sub Run() MyBase.Run() End Sub Private Sub FetchGateMoves(ByVal startDate As Date, ByVal endDate As Date) endDate = endDate.AddDays(1) _view.GateData = (From item In _context.Logs.Codeco.SetMergeOption(Data.Entity.Core.Objects.MergeOption.OverwriteChanges) Where item.EventTime > startDate And item.EventTime < endDate Order By item.EventTime Select New GateLog With { .AcceptedTime = If(item.RetrySucceeded, item.Logged), .ReceivedTime = item.Logged, .EventTime = item.EventTime, .Booking = item.Booking, .Container = item.Container, .Direction = item.Direction, .EmptyLaden = If(item.IsEmpty, "Empty", "Laden"), .Equipment = item.Equipment, .MatchedGate = item.Location.Name, .Message = item.Message, .Sender = item.Sender, .Succeeded = If(item.Succeeded, "Succeeded", "Failed")}).ToList End Sub Private Sub FetchLoadDischargeMoves(ByVal startDate As Date, ByVal endDate As Date) endDate = endDate.AddDays(1) _view.LoadDischargeData = (From item In _context.Logs.Coarri.SetMergeOption(Data.Entity.Core.Objects.MergeOption.OverwriteChanges) Where item.EventTime > startDate And item.EventTime < endDate Order By item.EventTime Select New LoadDischargeLog With {.EventTime = item.EventTime, .Booking = item.BookingRef, .Container = item.Container, .Sender = item.Sender, .Direction = If(item.IsLoad, "Load", "Discharge"), .EmptyLaden = If(item.IsEmpty, "Empty", "Laden"), .Equipment = item.Equipment, .Sailing = item.SailingRef, .Vessel = item.Vessel}).ToList End Sub Protected Overrides Sub OnSubmitChanges() Throw New InvalidOperationException End Sub Private Sub _view_FetchData(ByVal sender As ViewInterfaces.Admin.IEdiLogView, ByVal type As ViewInterfaces.Admin.IEdiLogView.LogType, ByVal startDate As Date, ByVal endDate As Date) Handles _view.FetchData If type = IEdiLogView.LogType.Gate Then FetchGateMoves(startDate, endDate) Else FetchLoadDischargeMoves(startDate, endDate) End If End Sub Private Sub _view_Drilldown(sender As Object, container As String, reference As String) Handles _view.Drilldown If String.IsNullOrWhiteSpace(container) = False Then Drilldown.ToContainer(container) End If If String.IsNullOrWhiteSpace(reference) = False Then If Text.RegularExpressions.Regex.Match(reference, Core.RegularExpression.BookingReference).Success Then Drilldown.ToShippingJob(reference) ElseIf Text.RegularExpressions.Regex.Match(reference, Core.RegularExpression.ItineraryReference).Success Then Drilldown.ToItinerary(New DBKey(reference), Nothing) End If End If End Sub #Region " Summary Classes " Public Class GateLog Implements IEdiLogView.IGateLog Public Property AcceptedTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.AcceptedTime Public Property Booking As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Booking Public Property Container As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Container Public Property Direction As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Direction Public Property EmptyLaden As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.EmptyLaden Public Property Equipment As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Equipment Public Property EventTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.EventTime Public Property MatchedGate As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.MatchedGate Public Property Message As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Message Public Property ReceivedTime As Date Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.ReceivedTime Public Property Sender As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Sender Public Property Succeeded As String Implements ViewInterfaces.Admin.IEdiLogView.IGateLog.Succeeded End Class Public Class LoadDischargeLog Implements IEdiLogView.ILoadDischargeLog Public Property Booking As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Booking Public Property Container As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Container Public Property Direction As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Direction Public Property EmptyLaden As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.EmptyLaden Public Property Equipment As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Equipment Public Property EventTime As Date Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.EventTime Public Property Sailing As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Sailing Public Property Sender As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Sender Public Property Vessel As String Implements ViewInterfaces.Admin.IEdiLogView.ILoadDischargeLog.Vessel End Class #End Region End Class #End Region End Namespace
Firstly, it has stilled moved the region to the bottom of the file. However it has also wrapped the entire class in a region with the same name?!?
Here is a screenshot showing the change I made to the rules . Other than the region name, I believe it is exactly what you suggested?
Thank you for providing the screencasts and code samples.
> Here is a screencast that illustrates it working correctly on my PC
Take note that CodeRush has separate Code Cleanup settings for C# and Visual Basic. In you provided settings, the "Organize Members" rule is enabled for Visual Basic and is disabled for C#. It causes different behavior for C# and Visual Basic code samples on your side.
> However it has also wrapped the entire class in a region with the same name?!?
You're right. Please accept my apologies for the incomplete instructions in my previous post. I have attached the screencast that illustrates additional changes which are required to correct this behavior to this post.
> it has stilled moved the region to the bottom of the file.
I have reproduced this issue and we are working on it. As a temporary workaround, I suggest you enable the "Remove all regions" Code Cleanup rule and locate it before the "Organize Members" rule.
Take note that other region directives will be removed and after applying Code Cleanup, a file will contain only region directives that are added by the Organize Members feature.
Thanks Alexander - I should have realised that C#/VB had their own rulesets!
As for the workaround, I think I'll need to wait for a proper fix - removing all regions would be a bit too destructive. That's fine though, I've grown used to avoiding organize members once the file has more than skeleton content in it , so I can certainly wait a bit longer!
Thanks for your help,
Kevin
You are welcome, Kevin.