C#递归查找解决方案中所有项目中的引用

时间:2015-10-06 15:41:15

标签: c# visual-studio

我们有一个非常大的解决方案(140个项目)我们将不同的项目部署到不同的服务器。完成部署的成本很高(按时间),因此我们将尝试跟踪我们的更改,以确定哪些项目受更改影响,然后仅部署这些项目。

例如:

假设我们有一个项目“Integral Part 1”(IP1)和另一个“Integral Part 2”(IP2)。在IP2内部,我们有一个类,广告,有一个生成html链接的方法,GenerateLink。 GenerateLink由广告中的另一个方法GenerateAd调用。我修改了GenerateLink。

IP1呼入并使用IP2中提供的服务。因此,需要重新部署IP1,以便在IP1中显示更改。

这是一个简单的观点,但应该将问题联系起来。目前,我需要进入GenerateLink方法并查找所有引用,然后按照每个引用查找它们的所有引用。我重复这个过程,直到找到解决方案中所有项目的所有引用,这些引用在某种程度上受到我的更改的影响。

是否有某种方法可以自动执行此过程,并简单地以递归方式请求方法的所有引用?

我在搜索中找到的最接近的答案是:Programmatically find all references to a function recursively,但我认为这不是我想要的。这听起来更像是Visual Studio中已经找到的所有引用工具。

1 个答案:

答案 0 :(得分:5)

您可以使用Roslyn aka Microsoft.CodeAnalysis来实现此目的。你需要设置机器来解决它。

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RoslynCompiler
{
    class ReferenceFinder
    {
        public void Find(string methodName)
        {

            string solutionPath = @"C:\Users\...\ConsoleForEverything.sln";
            var msWorkspace = MSBuildWorkspace.Create();

            List<ReferencedSymbol> referencesToMethod = new List<ReferencedSymbol>();
            Console.WriteLine("Searching for method \"{0}\" reference in solution {1} ", methodName, Path.GetFileName(solutionPath));
            ISymbol methodSymbol = null;
            bool found = false;

            //You must install the MSBuild Tools or this line will throw an exception.

            var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
            foreach (var project in solution.Projects)
            {
                foreach (var document in project.Documents)
                {
                    var model = document.GetSemanticModelAsync().Result;

                    var methodInvocation = document.GetSyntaxRootAsync().Result;
                    InvocationExpressionSyntax node = null;
                    try
                    {
                        node = methodInvocation.DescendantNodes().OfType<InvocationExpressionSyntax>()
                         .Where(x => ((MemberAccessExpressionSyntax)x.Expression).Name.ToString() == methodName).FirstOrDefault();

                        if (node == null)
                            continue;
                    }
                    catch(Exception exception)
                    {
                        // Swallow the exception of type cast. 
                        // Could be avoided by a better filtering on above linq.
                        continue;
                    }

                    methodSymbol = model.GetSymbolInfo(node).Symbol;
                    found = true;
                    break;
                }

                if (found) break;
            }

            foreach (var item in SymbolFinder.FindReferencesAsync(methodSymbol, solution).Result)
            {
                foreach (var location in item.Locations)
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("Project Assembly -> {0}", location.Document.Project.AssemblyName);
                    Console.ResetColor();
                }

            }

            Console.WriteLine("Finished searching. Press any key to continue....");
        }
    }
}

在运行示例之前下载并安装以下项目:

.Net 4.6 runtime

.Net 4.6 targeting pack

MSBuildTools 2015

需要进行以下设置以避免MSBuildWorkspace引发异常的运行时异常 The type or namespace name 'MSBuild' does not exist in the namespace 'Microsoft.CodeAnalysis' (are you missing an assembly reference?) 因为nuget包中的程序集是基于4.5.2构建的。

创建一个针对.Net 4.6的控制台应用程序并安装nuget包: Microsoft.CodeAnalysis 1.0.0

上述代码的测试运行:

        ReferenceFinder finder = new ReferenceFinder();
        finder.Find("Read");

输出:

enter image description here

此程序可能需要更多增强,因为Roslyn更强大。但这应该会给你一个良好的开端。您可以浏览有关Roslyn的更多信息,并且可以从C#代码中完全控制项目解决方案代码等。

TODO:我将为这个控制台应用创建一个github项目,我很快就会更新这篇文章。