I tried this code in NDepend version 2018.1.1 with some changes made to the original code which was posted on stackoverflow. It is to get the Methods which have a circular dependencies (ie calling each other and forming a cyclic/circular code)
But this Code does not seem to work in the latest nDepend.
Note: the only difference from the other code on StackOverflow is that this one has this according to version 2018.1.1 requirement;
let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
The Code.....
// <Name>Avoid methods of a type to be in cycles</Name>
warnif count > 0
from t in Application.Types
.Where(t => t.ContainsMethodDependencyCycle != null &&
t.ContainsMethodDependencyCycle.Value)
// Optimization: restreint methods set
// A method involved in a cycle necessarily have a null Level.
let methodsSuspect = t.Methods.Where(m => m.Level == null)
// hashset is used to avoid iterating again on methods already caught in a cycle.
let hashset = new HashSet<IMethod>()
from suspect in methodsSuspect
// By commenting this line, the query matches all methods involved in a cycle.
where !hashset.Contains(suspect)
// Define 2 code metrics
// - Methods depth of is using indirectly the suspect method.
// - Methods depth of is used by the suspect method indirectly.
// Note: for direct usage the depth is equal to 1.
let methodsUserDepth = methodsSuspect.DepthOfIsUsing(suspect)
let methodsUsedDepth = methodsSuspect.DepthOfIsUsedBy(suspect)
// Select methods that are both using and used by methodSuspect
let usersAndUsed = from n in methodsSuspect where
methodsUserDepth[n] > 0 &&
methodsUsedDepth[n] > 0
select n
where usersAndUsed.Count() > 0
// Here we've found method(s) both using and used by the suspect method.
// A cycle involving the suspect method is found!
let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
// Fill hashset with methods in the cycle.
// .ToArray() is needed to force the iterating process.
let unused1 = (from n in cycle let unused2 = hashset.Add(n) select n).ToArray()
select new { suspect, cycle }
The query provided works fine on my end to find cycles of methods inside a type.
For general cycle of methods (no matter their parent type) just modify the beginning of the query this way.
//from t in Application.Types
// .Where(t => t.ContainsMethodDependencyCycle != null &&
// t.ContainsMethodDependencyCycle.Value)
// Optimization: restreint methods set
// A method involved in a cycle necessarily have a null Level.
let methodsSuspect = Application.Methods.Where(m => m.Level == null)
Also increase in the NDepend > Options > CQLinq query execution time-out to 60 seconds because the query can be slow on a large code base with all graph traversal.
Keep in mind that a cycle is not necessarily as simple as A calls B calls C calls A. A cycle is a set of methods where from any method, there is a path to any other method in the cycle. It can be quite complex like:
To visualize a method cycle just export it to the code graph:
Typically to break cycles, start by breaking mutual dependencies, like A calls B and B calls A.
A method cycle is not necessarily a code smell, many GoF design patterns for example rely on a method cycle.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.