繁体   English   中英

解析 Visual Studio 解决方案文件

[英]Parsing Visual Studio Solution files

如何解析 .NET 中的 Visual Studio 解决方案 (SLN) 文件? 我想编写一个应用程序,将多个解决方案合并为一个,同时保存相对构建顺序。

Microsoft.Build 程序集的 .NET 4.0 版本在 Microsoft.Build.Construction 命名空间中包含一个解析 Visual Studio 解决方案文件的 SolutionParser class。

不幸的是,这个 class 是内部的,但我已经将其中的一些功能包装在 class 中,它使用反射来获取一些您可能会发现有用的常见属性。

public class Solution
{
    //internal class SolutionParser
    //Name: Microsoft.Build.Construction.SolutionParser
    //Assembly: Microsoft.Build, Version=4.0.0.0

    static readonly Type s_SolutionParser;
    static readonly PropertyInfo s_SolutionParser_solutionReader;
    static readonly MethodInfo s_SolutionParser_parseSolution;
    static readonly PropertyInfo s_SolutionParser_projects;

    static Solution()
    {
        s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if (s_SolutionParser != null)
        {
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
        }
    }

    public List<SolutionProject> Projects { get; private set; }

    public Solution(string solutionFileName)
    {
        if (s_SolutionParser == null)
        {
            throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
        }
        var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);
        using (var streamReader = new StreamReader(solutionFileName))
        {
            s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
            s_SolutionParser_parseSolution.Invoke(solutionParser, null);
        }
        var projects = new List<SolutionProject>();
        var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);
        for (int i = 0; i < array.Length; i++)
        {
            projects.Add(new SolutionProject(array.GetValue(i)));
        }
        this.Projects = projects;
    }
}

[DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
public class SolutionProject
{
    static readonly Type s_ProjectInSolution;
    static readonly PropertyInfo s_ProjectInSolution_ProjectName;
    static readonly PropertyInfo s_ProjectInSolution_RelativePath;
    static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
    static readonly PropertyInfo s_ProjectInSolution_ProjectType;

    static SolutionProject()
    {
        s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if (s_ProjectInSolution != null)
        {
            s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty("ProjectType", BindingFlags.NonPublic | BindingFlags.Instance);
        }
    }

    public string ProjectName { get; private set; }
    public string RelativePath { get; private set; }
    public string ProjectGuid { get; private set; }
    public string ProjectType { get; private set; }

    public SolutionProject(object solutionProject)
    {
        this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;
        this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;
        this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;
        this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(solutionProject, null).ToString();
    }
}

请注意,您必须将目标框架更改为“.NET Framework 4”(不是客户端配置文件)才能将 Microsoft.Build 引用添加到您的项目。

在 Visual Studio 2015 中,现在有一个可公开访问的SolutionFile class 可用于解析解决方案文件:

using Microsoft.Build.Construction;
var _solutionFile = SolutionFile.Parse(path);

此 class 可在Microsoft.Build.dll 14.0.0.0程序集中找到。 就我而言,它位于:

C:\Program Files (x86)\Reference Assemblies\Microsoft\MSBuild\v14.0\Microsoft.Build.dll

感谢菲尔指出这一点

我不知道是否有人仍在寻找解决此问题的方法,但我遇到了一个似乎可以满足需要的项目。 https://slntools.codeplex.com/此工具的功能之一是将多个解决方案合并在一起。

JetBrains (Resharper 的创建者)在其程序集中具有公共sln 解析能力(无需反射)。 它可能比此处建议的现有开源解决方案更强大(更不用说 ReGex hacks)。 您需要做的就是:

  • 下载ReSharper 命令行工具(免费)。
  • 添加以下内容作为对您项目的引用
    • JetBrains.Platform.ProjectModel
    • JetBrains.Platform.Util
    • JetBrains.Platform.Interop.WinApi

该库没有文档记录,但 Reflector(或者实际上是 dotPeek)是您的朋友。 例如:

public static void PrintProjects(string solutionPath)
{
    var slnFile = SolutionFileParser.ParseFile(FileSystemPath.Parse(solutionPath));
    foreach (var project in slnFile.Projects)
    {
        Console.WriteLine(project.ProjectName);
        Console.WriteLine(project.ProjectGuid);
        Console.WriteLine(project.ProjectTypeGuid);
        foreach (var kvp in project.ProjectSections)
        {
            Console.WriteLine(kvp.Key);
            foreach (var projectSection in kvp.Value) 
            {
                Console.WriteLine(projectSection.SectionName);
                Console.WriteLine(projectSection.SectionValue);
                foreach (var kvpp in projectSection.Properties)
                {
                    Console.WriteLine(kvpp.Key); 
                    Console.WriteLine(string.Join(",", kvpp.Value));
                }
            }
        }
    }
}

我不能真正为您提供图书馆,我猜那里不存在图书馆。 但是我花了很多时间在批量编辑场景中处理 .sln 文件,我发现 Powershell 是完成这项任务的一个非常有用的工具。 .SLN 格式非常简单,几乎可以用一些快速而肮脏的表达式来完全解析。 例如

包含的项目文件。

gc ConsoleApplication30.sln | 
  ? { $_ -match "^Project" } | 
  %{ $_ -match ".*=(.*)$" | out-null ; $matches[1] } | 
  %{ $_.Split(",")[1].Trim().Trim('"') }

它并不总是很漂亮,但它是进行批处理的有效方法。

我们通过编写一个 Visual Studio 插件解决了一个类似的自动合并解决方案的问题,该插件创建了一个新的解决方案,然后搜索 *.sln 文件并将它们导入到新的解决方案中:

dte2.Solution.AddFromFile(solutionPath, false);

我们的问题略有不同,因为我们希望 VS 为我们整理构建顺序,因此我们在可能的情况下将任何 dll 引用转换为项目引用。

然后,我们通过 COM 自动化运行 VS,将其自动化到构建过程中。

这个解决方案有点 Heath Robinson,但优点是 VS 正在编辑,所以我们的代码不依赖于 sln 文件的格式。 当我们从 VS 2005 迁移到 2008 并再次迁移到 2010 时,这很有帮助。

一切都很好,但我也想获得 sln 生成能力——在上面的代码快照中,你只是解析.sln 文件——我想做类似的事情,除了能够通过对 .sln 文件的轻微修改重新生成 sln . 例如,这种情况可以为不同的 .NET 平台移植相同的项目。 目前它只是 sln 重新生成,但稍后我会将其扩展到项目。

我想我还想展示正则表达式和本机接口的强大功能。 (更少的代码,更多的功能)

更新 4.1.2017我为 parsing.sln 解决方案创建了单独的 svn 存储库: https://sourceforge.net/p/syncproj/code/HEAD/tree/

下面是我自己的代码示例片段(前身)。 您可以自由使用它们中的任何一个。

将来,基于 svn 的解决方案解析代码也可能会更新生成功能。

更新 4.2.2017 SVN中的源代码也支持.sln 生成。

using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Text;


public class Program
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class SolutionProject
    {
        public string ParentProjectGuid;
        public string ProjectName;
        public string RelativePath;
        public string ProjectGuid;

        public string AsSlnString()
        { 
            return "Project(\"" + ParentProjectGuid + "\") = \"" + ProjectName + "\", \"" + RelativePath + "\", \"" + ProjectGuid + "\"";
        }
    }

/// <summary>
/// .sln loaded into class.
/// </summary>
public class Solution
{
    public List<object> slnLines;       // List of either String (line format is not intresting to us), or SolutionProject.

    /// <summary>
    /// Loads visual studio .sln solution
    /// </summary>
    /// <param name="solutionFileName"></param>
    /// <exception cref="System.IO.FileNotFoundException">The file specified in path was not found.</exception>
    public Solution( string solutionFileName )
    {
        slnLines = new List<object>();
        String slnTxt = File.ReadAllText(solutionFileName);
        string[] lines = slnTxt.Split('\n');
        //Match string like: Project("{66666666-7777-8888-9999-AAAAAAAAAAAA}") = "ProjectName", "projectpath.csproj", "{11111111-2222-3333-4444-555555555555}"
        Regex projMatcher = new Regex("Project\\(\"(?<ParentProjectGuid>{[A-F0-9-]+})\"\\) = \"(?<ProjectName>.*?)\", \"(?<RelativePath>.*?)\", \"(?<ProjectGuid>{[A-F0-9-]+})");

        Regex.Replace(slnTxt, "^(.*?)[\n\r]*$", new MatchEvaluator(m =>
            {
                String line = m.Groups[1].Value;

                Match m2 = projMatcher.Match(line);
                if (m2.Groups.Count < 2)
                {
                    slnLines.Add(line);
                    return "";
                }

                SolutionProject s = new SolutionProject();
                foreach (String g in projMatcher.GetGroupNames().Where(x => x != "0")) /* "0" - RegEx special kind of group */
                    s.GetType().GetField(g).SetValue(s, m2.Groups[g].ToString());

                slnLines.Add(s);
                return "";
            }), 
            RegexOptions.Multiline
        );
    }

    /// <summary>
    /// Gets list of sub-projects in solution.
    /// </summary>
    /// <param name="bGetAlsoFolders">true if get also sub-folders.</param>
    public List<SolutionProject> GetProjects( bool bGetAlsoFolders = false )
    {
        var q = slnLines.Where( x => x is SolutionProject ).Select( i => i as SolutionProject );

        if( !bGetAlsoFolders )  // Filter away folder names in solution.
            q = q.Where( x => x.RelativePath != x.ProjectName );

        return q.ToList();
    }

    /// <summary>
    /// Saves solution as file.
    /// </summary>
    public void SaveAs( String asFilename )
    {
        StringBuilder s = new StringBuilder();

        for( int i = 0; i < slnLines.Count; i++ )
        {
            if( slnLines[i] is String ) 
                s.Append(slnLines[i]);
            else
                s.Append((slnLines[i] as SolutionProject).AsSlnString() );

            if( i != slnLines.Count )
                s.AppendLine();
        }

        File.WriteAllText(asFilename, s.ToString());
    }
}


    static void Main()
    {
        String projectFile = @"yourown.sln";

        try
        {
            String outProjectFile = Path.Combine(Path.GetDirectoryName(projectFile), Path.GetFileNameWithoutExtension(projectFile) + "_2.sln");
            Solution s = new Solution(projectFile);
            foreach( var proj in s.GetProjects() )
            {
                Console.WriteLine( proj.RelativePath );
            }

            SolutionProject p = s.GetProjects().Where( x => x.ProjectName.Contains("Plugin") ).First();
            p.RelativePath = Path.Combine( Path.GetDirectoryName(p.RelativePath) , Path.GetFileNameWithoutExtension(p.RelativePath) + "_Variation" + ".csproj");

            s.SaveAs(outProjectFile);

        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
}

我阐述,确定MSBuild类可以用来操作底层结构。 稍后我将在我的 web 网站上提供更多代码。

// VSSolution

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using AbstractX.Contracts;

namespace VSProvider
{
    public class VSSolution : IVSSolution
    {
        //internal class SolutionParser 
        //Name: Microsoft.Build.Construction.SolutionParser 
        //Assembly: Microsoft.Build, Version=4.0.0.0 

        static readonly Type s_SolutionParser;
        static readonly PropertyInfo s_SolutionParser_solutionReader;
        static readonly MethodInfo s_SolutionParser_parseSolution;
        static readonly PropertyInfo s_SolutionParser_projects;
        private string solutionFileName;
        private List<VSProject> projects;

        public string Name
        {
            get
            {
                return Path.GetFileNameWithoutExtension(solutionFileName);
            }
        }

        public IEnumerable<IVSProject> Projects
        {
            get
            {
                return projects;
            }
        }

        static VSSolution()
        {
            s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        public string SolutionPath
        {
            get
            {
                var file = new FileInfo(solutionFileName);

                return file.DirectoryName;
            }
        }

        public VSSolution(string solutionFileName)
        {
            if (s_SolutionParser == null)
            {
                throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
            }

            var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);

            using (var streamReader = new StreamReader(solutionFileName))
            {
                s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
                s_SolutionParser_parseSolution.Invoke(solutionParser, null);
            }

            this.solutionFileName = solutionFileName;

            projects = new List<VSProject>();
            var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);

            for (int i = 0; i < array.Length; i++)
            {
                projects.Add(new VSProject(this, array.GetValue(i)));
            }
        }

        public void Dispose()
        {
        }
    }
}

// VSProject

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Xml;
using AbstractX.Contracts;
using System.Collections;

namespace VSProvider
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class VSProject : IVSProject
    {
        static readonly Type s_ProjectInSolution;
        static readonly Type s_RootElement;
        static readonly Type s_ProjectRootElement;
        static readonly Type s_ProjectRootElementCache;
        static readonly PropertyInfo s_ProjectInSolution_ProjectName;
        static readonly PropertyInfo s_ProjectInSolution_ProjectType;
        static readonly PropertyInfo s_ProjectInSolution_RelativePath;
        static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
        static readonly PropertyInfo s_ProjectRootElement_Items;

        private VSSolution solution;
        private string projectFileName;
        private object internalSolutionProject;
        private List<VSProjectItem> items;
        public string Name { get; private set; }
        public string ProjectType { get; private set; }
        public string RelativePath { get; private set; }
        public string ProjectGuid { get; private set; }

        public string FileName
        {
            get
            {
                return projectFileName;
            }
        }

        static VSProject()
        {
            s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty("ProjectType", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);

            s_ProjectRootElement = Type.GetType("Microsoft.Build.Construction.ProjectRootElement, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
            s_ProjectRootElementCache = Type.GetType("Microsoft.Build.Evaluation.ProjectRootElementCache, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectRootElement_Items = s_ProjectRootElement.GetProperty("Items", BindingFlags.Public | BindingFlags.Instance);
        }

        public IEnumerable<IVSProjectItem> Items
        {
            get
            {
                return items;
            }
        }

        public VSProject(VSSolution solution, object internalSolutionProject)
        {
            this.Name = s_ProjectInSolution_ProjectName.GetValue(internalSolutionProject, null) as string;
            this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(internalSolutionProject, null).ToString();
            this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(internalSolutionProject, null) as string;
            this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(internalSolutionProject, null) as string;

            this.solution = solution;
            this.internalSolutionProject = internalSolutionProject;

            this.projectFileName = Path.Combine(solution.SolutionPath, this.RelativePath);

            items = new List<VSProjectItem>();

            if (this.ProjectType == "KnownToBeMSBuildFormat")
            {
                this.Parse();
            }
        }

        private void Parse()
        {
            var stream = File.OpenRead(projectFileName);
            var reader = XmlReader.Create(stream);
            var cache = s_ProjectRootElementCache.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(new object[] { true });
            var rootElement = s_ProjectRootElement.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(new object[] { reader, cache });

            stream.Close();

            var collection = (ICollection)s_ProjectRootElement_Items.GetValue(rootElement, null);

            foreach (var item in collection)
            {
                items.Add(new VSProjectItem(this, item));
            }

        }

        public IEnumerable<IVSProjectItem> EDMXModels
        {
            get 
            {
                return this.items.Where(i => i.ItemType == "EntityDeploy");
            }
        }

        public void Dispose()
        {
        }
    }
}

// VSProjectItem

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Xml;
using AbstractX.Contracts;

namespace VSProvider
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class VSProjectItem : IVSProjectItem
    {
        static readonly Type s_ProjectItemElement;
        static readonly PropertyInfo s_ProjectItemElement_ItemType;
        static readonly PropertyInfo s_ProjectItemElement_Include;

        private VSProject project;
        private object internalProjectItem;
        private string fileName;

        static VSProjectItem()
        {
            s_ProjectItemElement = Type.GetType("Microsoft.Build.Construction.ProjectItemElement, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectItemElement_ItemType = s_ProjectItemElement.GetProperty("ItemType", BindingFlags.Public | BindingFlags.Instance);
            s_ProjectItemElement_Include = s_ProjectItemElement.GetProperty("Include", BindingFlags.Public | BindingFlags.Instance);
        }

        public string ItemType { get; private set; }
        public string Include { get; private set; }

        public VSProjectItem(VSProject project, object internalProjectItem)
        {
            this.ItemType = s_ProjectItemElement_ItemType.GetValue(internalProjectItem, null) as string;
            this.Include = s_ProjectItemElement_Include.GetValue(internalProjectItem, null) as string;
            this.project = project;
            this.internalProjectItem = internalProjectItem;

            // todo - expand this

            if (this.ItemType == "Compile" || this.ItemType == "EntityDeploy")
            {
                var file = new FileInfo(project.FileName);

                fileName = Path.Combine(file.DirectoryName, this.Include);
            }
        }

        public byte[] FileContents
        {
            get 
            {
                return File.ReadAllBytes(fileName);
            }
        }

        public string Name
        {
            get 
            {
                if (fileName != null)
                {
                    var file = new FileInfo(fileName);

                    return file.Name;
                }
                else
                {
                    return this.Include;
                }
            }
        }
    }
}

@john-leidegren 的回答很棒。 对于 VS2015 之前的版本,这很有用。 但是有一个小错误,因为缺少检索配置的代码。 所以想添加它,以防有人正在努力使用此代码。
增强非常简单:

    public class Solution
{
    //internal class SolutionParser
    //Name: Microsoft.Build.Construction.SolutionParser
    //Assembly: Microsoft.Build, Version=4.0.0.0

    static readonly Type s_SolutionParser;
    static readonly PropertyInfo s_SolutionParser_solutionReader;
    static readonly MethodInfo s_SolutionParser_parseSolution;
    static readonly PropertyInfo s_SolutionParser_projects;
    static readonly PropertyInfo s_SolutionParser_configurations;//this was missing in john's answer


    static Solution()
    {
        s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if ( s_SolutionParser != null )
        {
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_configurations = s_SolutionParser.GetProperty("SolutionConfigurations", BindingFlags.NonPublic | BindingFlags.Instance); //this was missing in john's answer

            // additional info:
            var PropNameLst = GenHlp_PropBrowser.PropNamesOfType(s_SolutionParser);
            // the above call would yield something like this:
            // [ 0] "SolutionParserWarnings"        string
            // [ 1] "SolutionParserComments"        string
            // [ 2] "SolutionParserErrorCodes"      string
            // [ 3] "Version"                       string
            // [ 4] "ContainsWebProjects"           string
            // [ 5] "ContainsWebDeploymentProjects" string
            // [ 6] "ProjectsInOrder"               string
            // [ 7] "ProjectsByGuid"                string
            // [ 8] "SolutionFile"                  string
            // [ 9] "SolutionFileDirectory"         string
            // [10] "SolutionReader"                string
            // [11] "Projects"                      string
            // [12] "SolutionConfigurations"        string
        }
    }

    public List<SolutionProject> Projects { get; private set; }
    public List<SolutionConfiguration> Configurations { get; private set; }

   //...
   //...
   //... no change in the rest of the code
}

作为附加帮助,提供简单的代码来浏览 @oasten 建议的System.Type的属性。

public class GenHlp_PropBrowser
{
    public static List<string> PropNamesOfClass(object anObj)
    {
        return anObj == null ? null : PropNamesOfType(anObj.GetType());
    }
    public static List<String> PropNamesOfType(System.Type aTyp)
    {
        List<string> retLst = new List<string>();
        foreach ( var p in aTyp.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) )
        {
            retLst.Add(p.Name);
        }
        return retLst;
    }
}

感谢@John Leidegren,他提供了一种有效的方法。 我写了一个 hlper class 因为我不能使用他的代码,找不到s_SolutionParser_configurations和没有 FullName 的项目。

代码在github中,可以获取全名项目。

并且代码无法获取SolutionConfiguration。

但是当你开发一个 vsx 时,vs 会说找不到Microsoft.Build.dll ,所以你可以尝试使用 dte 来获取所有项目。

使用dte获取所有项目的代码在github

对于它的价值,我现在创建了一个小项目来读取 nuget 上可用的 sln 和 proj 文件:

https://www.nuget.org/packages/ByteDev.DotNet/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM