【问题标题】:Static analysis of .net assembly.net 程序集的静态分析
【发布时间】:2010-12-12 22:23:07
【问题描述】:

我有一个 C# 项目,我需要找到所有私有方法,这些方法不是直接或间接从任何其他公共方法调用的。

另外,对于从公共方法调用的每个私有方法,我需要知道它是哪个公共方法。然后我将确定该方法是否真的是从该类的客户端调用的,如果不是,我将能够将其删除。

过去,我使用 Lutz Rorder 的代码,它是 Reflector 的基础——它可以选择分析 IL 代码并在其之上提供对象模型。我现在找不到此代码。

有什么建议吗? 也许指向那个 Lutz Rorder 代码?

萨尔

【问题讨论】:

    标签: static analysis reflector il


    【解决方案1】:

    您应该查看Nitriq Static Code Analysis for .Net - 他们有一个免费的社区版,而且他们的完整许可非常合理。

    【讨论】:

      【解决方案2】:

      正如 Thomas 所指出的,工具 NDepend 可以帮助您在 .NET 代码库中找到未使用的代码。 免责声明:我是该工具的开发者之一。

      NDepend 建议写Code Rule over LINQ Query (CQLinq)。大约200 default code rules 被提议,其中3 个专门用于未使用/死代码检测:

      NDepend 集成在 Visual Studio 中,因此这些规则可以是 checked/browsed/edited right inside the IDE。该工具还可以集成到您的 CI 流程中,它可以构建 reports 来显示违反的规则和罪魁祸首代码元素。

      如果你点击上面这3个链接看这些规则的源代码,你会发现关于类型和方法的部分有点复杂。这是因为它们不仅检测未使用的类型和方法,还检测到被未使用的死类型和方法使用的类型和方法(递归)。

      这是静态分析,因此规则名称中的前缀Potentially。如果代码元素通过反射使用,这些规则可能会将其视为未使用,但事实并非如此。

      除了使用这 3 条规则之外,我还建议通过测试来衡量代码覆盖率,并努力实现全面覆盖。通常,您会看到测试无法覆盖的代码实际上是可以安全丢弃的未使用/死代码。这在不清楚代码分支是否可达的复杂算法中特别有用。


      另外,对于从公共方法调用的每个私有方法,我需要知道它是哪个公共方法。

      要获取此信息,使用 CQLinq 您只需编写:

      from m in Application.Methods
      where m.IsPrivate
      let publicMethodsCallingMe = m.MethodsCallingMe.Where(m1 => m1.IsPublic)
      where publicMethodsCallingMe.Count() > 0
      select new { m, publicMethodsCallingMe }
      

      查询结果将很容易浏览:

      【讨论】:

        【解决方案3】:

        嗯,这样做的唯一方法(至少我知道的唯一方法......)意味着使用商业(但不那么昂贵)工具,即NDepend

        除此之外,您还可以针对已编译的程序集编写类似 SQL 的查询,从而实现非常精细的分析。他们称之为 CQL,语法不言自明,NDepend 的 IntelliSense/自动完成支持以及一般帮助/文档都非常好。

        (AFAIK 他们还提供功能齐全的试用版,如果对您有帮助的话......)

        HTH!

        【讨论】:

          【解决方案4】:

          不确定它是否能满足所有这些需求,但 FXCop 会为您完成大部分这些需求,并且还会帮助制定大量编码标准。无论哪种方式,都值得在您的 c# 代码上运行。

          FXCop (MSDN)

          【讨论】:

          • FxCop 将找到未使用的私有方法。至于用到的,在方法上右击,从菜单中选择“查找所有引用”。
          【解决方案5】:

          Reflector 仍然具有此功能。只需右键单击该方法,然后单击分析。按照树视图中的链接进行操作。

          您没有说是否需要在代码中执行,或者只是“直观地”。

          如果需要代码,我相信你可以使用 Reflector SDK。

          【讨论】:

            【解决方案6】:

            我也许可以使用 PowerCommands for Reflector 插件 (http://powercommands.codeplex.com) 中的查询编辑器来帮助您解决这个问题……我今晚看看我能想出什么,然后明天再告诉您。

            否则,您也可以使用 CCI 或 Cecil 编写一个快速应用程序。

            查询:

            from a in AssemblyManager.Assemblies.Cast<IAssembly>()
            where a.Name != "mscorlib" 
                && !a.Name.Contains("System")
            from m in a.Modules.Cast<IModule>()
            from t in m.Types.Cast<ITypeDeclaration>()
            from mt in t.Methods.Cast<IMethodDeclaration>()
            where mt.Visibility == MethodVisibility.Public 
                && !mt.RuntimeSpecialName 
                && !mt.SpecialName 
                && mt.Body is IMethodBody
            from i in ((IMethodBody)mt.Body).Instructions.Cast<IInstruction>()
            where i != null 
                && i.Value != null 
                && i.Value is IMethodReference 
                && ((IMethodReference)i.Value).Resolve() != null
                && ((IMethodReference)i.Value).Resolve().Visibility == MethodVisibility.Private
            select new { 
                CallingMethod=t.Namespace + "." + t.Name + "." + mt.Name, 
                PrivateReferencedMethod=((ITypeReference)((IMemberReference)((IMethodReference)i.Value).Resolve()).DeclaringType).Namespace + "."
                    + ((ITypeReference)((IMemberReference)((IMethodReference)i.Value).Resolve()).DeclaringType).Name + "."
                    + ((IMethodReference)i.Value).ToString()
            }
            

            【讨论】:

            • 第二次阅读您的问题后 - 如果您有兴趣编写一个可以满足您需求的实用程序 - 请查看:ccimetadata.codeplex.com
            • 如果您想尝试从 Reflector 获取信息,您可以使用以下查询来获取公共方法调用的所有私有方法。注意:假设您的所有依赖项都已加载到 Reflector 中......如果您收到一个对话框,要求您找到一个程序集,您必须单击“跳过”,否则它将杀死 Reflector。
            • 我还添加了过滤以忽略 mscorlib 或任何系统程序集以及忽略特殊命名方法(构造函数和属性方法)。
            • 我有一篇介绍查询编辑器的博客文章:jasonhaley.com/blog/post/2009/10/18/…,我应该在接下来的一两天内再发布一篇更详细的文章。
            猜你喜欢
            • 1970-01-01
            • 2014-04-28
            • 2011-12-01
            • 2013-08-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-24
            相关资源
            最近更新 更多