c# - 如何以编程方式检查解决方案中的引用是否配置正确

2024-02-07

我们遇到了一些构建错误,需要手动修复引用。 我想以编程方式检查是否定义了项目引用而不是 dll 引用: 因此,请检查解决方案中的所有引用,并针对每个项目检查引用的定义是否正确。这样相关的依赖就会被正确配置。

有人知道现有的解决方案吗?我想要一个在门控签入之前运行的验证工具。


我编写了这样一个工具来处理我们的“.csproj”文件。我的工具递归地遍历文件夹层次结构,处理每个“.csproj”文件以验证它是否符合我们的标准(例如要求打开代码分析、警告作为错误、强名称签名等)。

不管怎样,我最近重写了很多内容以使用 Linq-to-XML 来处理文件,结果比我七年前最初编写时要容易得多......

CSProj 处理的核心是由一个类完成的,该类期望作为输入(通过构造函数)“.csproj”项目文件的完整路径名。

它使用 Linq-to-XML 来解析文件的各个部分。看看它 - 希望它能帮助您入门。

我还建议在尝试各种 XML 查询来获取 .csproj 文件的各个部分时使用 Linqpad。

该代码在某种程度上特定于我们的要求,但它应该为您提供一个起点。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;


namespace CreateMSBuildProject
{
    /// <summary>Encapsulates a ".csproj" file.</summary>

    sealed class CSProj
    {
        /// <summary>Encapsulates information about a particular build configuration.</summary>

        public sealed class BuildConfiguration
        {
            public BuildConfiguration(XElement configuration)
            {
                // ReSharper disable PossibleNullReferenceException

                OutputPath             = configuration.Element(_ns + "OutputPath").Value;
                WarningLevel           = warningLevel(configuration);
                CodeAnalysisRuleset    = configuration.Element(_ns + "CodeAnalysisRuleSet").Value;
                TreatWarningsAsErrors  = isTrue(configuration.Element(_ns + "TreatWarningsAsErrors"));
                IsCodeAnalysisEnabled  = isTrue(configuration.Element(_ns + "RunCodeAnalysis"));
                IsCodeContractsEnabled = isTrue(configuration.Element(_ns + "CodeContractsEnableRuntimeChecking"));

                // ReSharper restore PossibleNullReferenceException
            }

            public bool IsDebug
            {
                get
                {
                    return (string.Compare(OutputPath, "bin\\debug\\", StringComparison.OrdinalIgnoreCase) == 0);
                }
            }

            public bool IsRelease
            {
                get
                {
                    return(string.Compare(OutputPath, "bin\\release\\", StringComparison.OrdinalIgnoreCase) == 0);
                }
            }

            static bool isTrue(XElement element) // Defaults to false if element is null.
            {
                return (element != null) && (string.Compare(element.Value, "true", StringComparison.OrdinalIgnoreCase) == 0);
            }

            static int warningLevel(XElement element) // Defaults to 4 if not set.
            {
                var level = element.Element(_ns + "WarningLevel");

                if (level != null)
                    return int.Parse(level.Value);
                else
                    return 4; // Default warning level is 4.
            }

            public readonly string OutputPath;
            public readonly string CodeAnalysisRuleset;
            public readonly bool   IsCodeAnalysisEnabled;
            public readonly bool   TreatWarningsAsErrors;
            public readonly bool   IsCodeContractsEnabled;
            public readonly int    WarningLevel;
        }

        /// <summary>Encapsulates information about a referenced assembly.</summary>

        public sealed class AssemblyReference
        {
            public AssemblyReference(XElement reference)
            {
                Include = reference.Attribute("Include").Value.Split(',')[0]; // Get rid of stuff after the first ","

                var hintElem = reference.Element(_ns+"HintPath");

                if (hintElem != null)
                    HintPath = hintElem.Value;
                else
                    HintPath = "";
            }

            public readonly string HintPath;
            public readonly string Include;
        }

        /// <summary>Constructor.</summary>

        public CSProj(string csprojFilePath)
        {
            if (!isValidProjFilePath(csprojFilePath))
                throw new ArgumentOutOfRangeException("csprojFilePath", csprojFilePath, "File does not exist, or filename does not end with '.csproj'.");

            // ReSharper disable PossibleMultipleEnumeration

            XDocument doc = XDocument.Load(csprojFilePath);

            var propertyGroups = getPropertyGroups(doc);

            _projectFilePath              = csprojFilePath;
            _outputType                   = getOutputType(propertyGroups);
            _assemblyName                 = getAssemblyName(propertyGroups);
            _targetFrameworkVersion       = getTargetFrameworkVersion(propertyGroups);
            _projectDependencies          = getProjectDependencies(doc);
            _targetFrameworkProfile       = getTargetFrameworkProfile(doc);
            _xmlDocumentationFiles        = getXmlDocumentationFiles(doc);
            _buildConfigurations          = getBuildConfigurations(doc);
            _assemblyReferences           = getAssemblyReferences(doc);
            _anyStaticCodeAnalysisEnabled = getAnyStaticCodeAnalysisEnabled(doc);
            _platformTargets              = getPlatformTargets(doc);

            // ReSharper restore PossibleMultipleEnumeration
        }

        #region Properties

        /// <summary>The project output type, e.g. "WinExe" or "Library".</summary>

        public string OutputType { get { return _outputType; }  }

        /// <summary>The project's output assembly name.</summary>

        public string AssemblyName { get { return _assemblyName; } }

        /// <summary>The target framework version, or 0.0 if not set.</summary>

        public double TargetFrameworkVersion { get { return _targetFrameworkVersion; } }

        /// <summary>The project dependencies - not to be confused with assembly references!</summary>

        public IEnumerable<string> ProjectDependencies { get { return _projectDependencies; } }

        public IEnumerable<string> XmlDocumentationFiles { get { return _xmlDocumentationFiles; } }

        public IEnumerable<BuildConfiguration> BuildConfigurations { get { return _buildConfigurations; } }

        public string TargetFrameworkProfile { get { return _targetFrameworkProfile; } }

        public IEnumerable<AssemblyReference> AssemblyReferences { get { return _assemblyReferences; } }

        public bool AnyStaticCodeAnalysisEnabled { get { return _anyStaticCodeAnalysisEnabled; } }

        public string ProjectFilePath { get { return _projectFilePath; } }

        public string[] PlatformTargets { get { return _platformTargets; } }

        #endregion Properties

        //—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

        static string[] getPlatformTargets(XDocument doc) 
        {
            var result = (from item in doc.Descendants(_ns + "PlatformTarget") select item.Value).ToArray();

            if (result.Length > 0)
                return result;
            else
                return new []{"AnyCPU"}; // If "PlatformTarget" is not specified, it defaults to "AnyCPU".
        }

        static IEnumerable<XElement> getPropertyGroups(XDocument doc)
        {
            // ReSharper disable PossibleNullReferenceException
            return doc.Element(_ns+"Project").Elements(_ns+"PropertyGroup");
            // ReSharper restore PossibleNullReferenceException
        }

        static string getOutputType(IEnumerable<XElement> propertyGroups)
        {
            return propertyGroups.Elements(_ns+"OutputType").First().Value;
        }

        static string getAssemblyName(IEnumerable<XElement> propertyGroups)
        {
            return propertyGroups.Elements(_ns+"AssemblyName").First().Value;
        }

        static double getTargetFrameworkVersion(IEnumerable<XElement> propertyGroups)
        {
            var targetFrameworkVersion = propertyGroups.Elements(_ns+"TargetFrameworkVersion").FirstOrDefault();

            if (targetFrameworkVersion != null)
                return double.Parse(targetFrameworkVersion.Value.Substring(1)); // Skip first character, which is "v"; eg like "v3.5"
            else
                return 0;
        }

        static string[] getProjectDependencies(XDocument doc)
        {
            return 
            (
                from item in doc.Descendants(_ns + "ProjectReference")
                select item.Attribute("Include").Value
            )
            .ToArray();
        }

        static string getTargetFrameworkProfile(XDocument doc)
        {
            var targetFrameworkProfile = doc.Descendants(_ns + "TargetFrameworkProfile").FirstOrDefault();

            if (targetFrameworkProfile != null)
                return targetFrameworkProfile.Value;
            else
                return "";
        }

        static string[] getXmlDocumentationFiles(XDocument doc)
        {
            return
            (
                from item in doc.Descendants(_ns+"DocumentationFile")
                select item.Value
            )
            .ToArray();
        }

        static BuildConfiguration[] getBuildConfigurations(XDocument doc)
        {
            var configGroups = from item in doc.Descendants(_ns+"PropertyGroup")
                               where item.Descendants(_ns+"OutputPath").Any()
                               select new BuildConfiguration(item);

            return configGroups.ToArray();
        }

        static AssemblyReference[] getAssemblyReferences(XDocument doc)
        {
            var references = from item in doc.Descendants(_ns + "Reference")
                             select new AssemblyReference(item);

            return references.ToArray();
        }

        static bool getAnyStaticCodeAnalysisEnabled(XDocument doc)
        {
            return doc.Descendants(_ns + "CodeContractsRunCodeAnalysis")
                .Where(item => item.Attribute("Condition") == null) // Some of these have a "Condition" attribute, which is OK.
                .Any(item => string.Compare(item.Value, "true", StringComparison.OrdinalIgnoreCase) == 0);
        }

        static bool isValidProjFilePath(string projFilePath)
        {
            return 
            (
                !string.IsNullOrWhiteSpace(projFilePath) 
                && (projFilePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) || projFilePath.EndsWith(".vbproj", StringComparison.OrdinalIgnoreCase))
                && File.Exists(projFilePath)
            );
        }

        static readonly XNamespace _ns = "http://schemas.microsoft.com/developer/msbuild/2003";

        readonly bool _anyStaticCodeAnalysisEnabled;

        readonly string _projectFilePath;
        readonly string _outputType;
        readonly string _assemblyName;
        readonly string _targetFrameworkProfile;
        readonly double _targetFrameworkVersion;

        readonly string[] _projectDependencies;
        readonly string[] _xmlDocumentationFiles;
        readonly string[] _platformTargets;

        readonly BuildConfiguration[]     _buildConfigurations;
        readonly AssemblyReference[] _assemblyReferences;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c# - 如何以编程方式检查解决方案中的引用是否配置正确 的相关文章

  • 检查两个数是否是彼此的排列?

    给定两个数字 a b 使得 1 例如 123 是 312 的有效排列 我也不想对数字中的数字进行排序 如果您指的是数字的字符 例如 1927 和 9721 则 至少 有几种方法 如果允许排序 一种方法是简单地sprintf将它们放入两个缓冲
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 使用 System.Text.Json 即时格式化 JSON 流

    我有一个未缩进的 Json 字符串 例如 hash 123 id 456 我想缩进字符串并将其序列化为 JSON 文件 天真地 我可以使用缩进字符串Newtonsoft如下 using Newtonsoft Json Linq JToken
  • clang 实例化后静态成员初始化

    这样的代码可以用 GCC 编译 但 clang 3 5 失败 include
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke

随机推荐