C# 如何在最新版本 2018.1.1 中使用 ndepend 获取 Project/Solution 中的循环方法
C# How to get the Circular Methods in a Project/Solution using ndepend in the latest version 2018.1.1
我在 NDepend 版本 2018.1.1 中尝试了此代码,并对发布在 Whosebug 上的原始代码进行了一些更改。就是获取循环依赖的Methods(即相互调用,形成cyclic/circular代码)
但是这段代码在最新的nDepend中似乎不起作用。
注意:与 Whosebug 上的其他代码唯一不同的是,根据版本 2018.1.1 的要求,此代码具有此功能;
let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
代码......
// <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 }
提供的查询在我这边工作正常,可以在一个类型中找到方法循环。
对于一般循环的方法(无论它们的父类型如何)只需以这种方式修改查询的开头。
//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)
还将 NDepend > 选项 > CQLinq 查询执行超时增加到 60 秒,因为在具有所有图形遍历的大型代码库上查询可能会很慢。
请记住,循环并不一定像 A 调用 B 调用 C 调用 A 那样简单。循环是一组方法,其中从任何方法到循环中的任何其他方法都有路径。它可能非常复杂,例如:
要可视化方法循环,只需将其导出到代码图中:
通常要打破循环,首先要打破相互依赖,比如 A 调用 B,B 调用 A。
方法循环不一定是代码味道,例如许多 GoF 设计模式都依赖于方法循环。
我在 NDepend 版本 2018.1.1 中尝试了此代码,并对发布在 Whosebug 上的原始代码进行了一些更改。就是获取循环依赖的Methods(即相互调用,形成cyclic/circular代码)
但是这段代码在最新的nDepend中似乎不起作用。
注意:与 Whosebug 上的其他代码唯一不同的是,根据版本 2018.1.1 的要求,此代码具有此功能;
let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
代码......
// <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 }
提供的查询在我这边工作正常,可以在一个类型中找到方法循环。
对于一般循环的方法(无论它们的父类型如何)只需以这种方式修改查询的开头。
//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)
还将 NDepend > 选项 > CQLinq 查询执行超时增加到 60 秒,因为在具有所有图形遍历的大型代码库上查询可能会很慢。
请记住,循环并不一定像 A 调用 B 调用 C 调用 A 那样简单。循环是一组方法,其中从任何方法到循环中的任何其他方法都有路径。它可能非常复杂,例如:
要可视化方法循环,只需将其导出到代码图中:
通常要打破循环,首先要打破相互依赖,比如 A 调用 B,B 调用 A。
方法循环不一定是代码味道,例如许多 GoF 设计模式都依赖于方法循环。