获取受 cqlinq 中的扩展方法影响的类型列表
Getting list of types that are effected by an extension method in cqlinq
如何在ndepend cqlinq中获取通过扩展方法扩展的类型列表?在 ndepend 已经存在的情况下,使用反射来编码这似乎有点笨拙。
NDepend 代码模型没有直接的方法来解析方法参数类型。因此,我们可以通过依赖于从方法名称中提取的字符串格式扩展类型名称的代码查询来得出令人满意的答案。但是这个查询过于复杂,并且在某些边缘情况下它无法正常工作(在下面解释)。
这是代码查询,由于使用了字典,即使在大型代码库上它也能快速运行:
//
// First let build dicoExtensionMethods
let dicoExtensionMethods =
(from m in Application.Methods
where m.IsExtensionMethod
// extract extended type simple name (with generic parameters like "IEnumerable<String>")
let beginIndex = m.Name.IndexOf("(") + 1
let endIndex = m.Name.IndexOf(',', beginIndex) > 0 ? m.Name.IndexOf(',', beginIndex) : m.Name.IndexOf(")", beginIndex)
let extendedTypeSimpleName1 = m.Name.Substring(beginIndex, endIndex - beginIndex)
// Take care of generic type first char, like "IEnumerable<"
let extendedTypeSimpleName2 = extendedTypeSimpleName1.IndexOf('<') == -1 ? extendedTypeSimpleName1 :
extendedTypeSimpleName1.Substring(0, extendedTypeSimpleName1.IndexOf('<') + 1 )
select new { m, extendedTypeSimpleName2 })
.ToLookup(pair => pair.extendedTypeSimpleName2)
.ToDictionary(g => g.Key, g=> g.Select(p =>p.m))
//
// Second for each type get extension methods from dicoExtensionMethods
from t in Types
// Format type name like "IEnumerable<"
let typeName = !t.IsGeneric ? t.SimpleName : t.Name.Substring(0, t.Name.IndexOf('<') + 1 )
where dicoExtensionMethods.ContainsKey(typeName)
let methods = dicoExtensionMethods[typeName]
select new { t, methods }
正如所写,由于类型名称格式的原因,它是一个复杂的查询,并且在大多数情况下都可以正常工作。
然而,当谈到扩展泛型类型时,它说例如 IEnumerable<T>
被扩展 IEnumerable<String>
和 IEnumerable<Int32>
的两种方法扩展。这是可以接受的,但不是 100% 正确。
此外,如果您扩展多个具有相同名称但具有不同泛型元数的类型(如 Func<T1,T2>
和 Func<T1,T2,T3>
),则此代码查询将无法正常工作。
如果您扩展多个具有相同名称的类型,在不同的程序集或命名空间中声明,则相同(无论如何这是一种代码味道)。
希望对您有所帮助!
如何在ndepend cqlinq中获取通过扩展方法扩展的类型列表?在 ndepend 已经存在的情况下,使用反射来编码这似乎有点笨拙。
NDepend 代码模型没有直接的方法来解析方法参数类型。因此,我们可以通过依赖于从方法名称中提取的字符串格式扩展类型名称的代码查询来得出令人满意的答案。但是这个查询过于复杂,并且在某些边缘情况下它无法正常工作(在下面解释)。
这是代码查询,由于使用了字典,即使在大型代码库上它也能快速运行:
//
// First let build dicoExtensionMethods
let dicoExtensionMethods =
(from m in Application.Methods
where m.IsExtensionMethod
// extract extended type simple name (with generic parameters like "IEnumerable<String>")
let beginIndex = m.Name.IndexOf("(") + 1
let endIndex = m.Name.IndexOf(',', beginIndex) > 0 ? m.Name.IndexOf(',', beginIndex) : m.Name.IndexOf(")", beginIndex)
let extendedTypeSimpleName1 = m.Name.Substring(beginIndex, endIndex - beginIndex)
// Take care of generic type first char, like "IEnumerable<"
let extendedTypeSimpleName2 = extendedTypeSimpleName1.IndexOf('<') == -1 ? extendedTypeSimpleName1 :
extendedTypeSimpleName1.Substring(0, extendedTypeSimpleName1.IndexOf('<') + 1 )
select new { m, extendedTypeSimpleName2 })
.ToLookup(pair => pair.extendedTypeSimpleName2)
.ToDictionary(g => g.Key, g=> g.Select(p =>p.m))
//
// Second for each type get extension methods from dicoExtensionMethods
from t in Types
// Format type name like "IEnumerable<"
let typeName = !t.IsGeneric ? t.SimpleName : t.Name.Substring(0, t.Name.IndexOf('<') + 1 )
where dicoExtensionMethods.ContainsKey(typeName)
let methods = dicoExtensionMethods[typeName]
select new { t, methods }
正如所写,由于类型名称格式的原因,它是一个复杂的查询,并且在大多数情况下都可以正常工作。
然而,当谈到扩展泛型类型时,它说例如 IEnumerable<T>
被扩展 IEnumerable<String>
和 IEnumerable<Int32>
的两种方法扩展。这是可以接受的,但不是 100% 正确。
此外,如果您扩展多个具有相同名称但具有不同泛型元数的类型(如 Func<T1,T2>
和 Func<T1,T2,T3>
),则此代码查询将无法正常工作。
如果您扩展多个具有相同名称的类型,在不同的程序集或命名空间中声明,则相同(无论如何这是一种代码味道)。
希望对您有所帮助!