【问题标题】:Setting MSBuild 'Condition' attribute via Visual Studio extension通过 Visual Studio 扩展设置 MSBuild 'Condition' 属性
【发布时间】:2012-09-11 22:12:00
【问题描述】:

我有一个 C# 项目,它采用几种不同的配置构建。某些源文件应始终包含在内,而某些源文件仅在某些配置中包含。到目前为止,我一直在使用 #if ... #endif 围绕整个文件执行此操作,但我希望创建一个小扩展来更好地执行此操作。

我创建了一个扩展,可以将项目添加到文件的上下文菜单中,但我找不到任何方法来设置项目文件中项目节点上的Condition 属性。

我查看了EnvDTE.ProjectItem 接口的Properties 集合,但在那里看不到任何有用的东西(除了BuildAction...我会回来讨论)。

然后我尝试在该项目上获取IVsBuildPropertyStorage 并调用SetItemAttribute()。这确实将信息添加到项目文件中,但作为这样的子元素:

<ItemGroup>
  <Compile Include="Program.cs">
    <Condition>%27%24%28Configuration%29%27==%27Debug%27</Condition>
  </Compile>
</ItemGroup>

当我想要达到的目标是:

<ItemGroup>
  <Compile Include="Program.cs" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>

还有一个IVsBuildPropertyStorage.SetPropertyValue(),但它会将类似的子元素添加到靠近顶部的PropertyGroup 部分,而不是添加到项目节点。

我查看了“项目子类型/风味”,但看起来它只会让我获得另一个 IVsBuildPropertyStorage,这似乎没有用。它们看起来确实能够处理很多复杂的事情,但有关该主题的文档似乎很少且含糊不清。

我看过一些描述如何使用 MSBuild 程序集直接加载和操作项目文件的帖子,但我不确定 什么时候 在不混淆 Visual Studio 和潜在的情况下这样做是否安全丢失更改,因为 VS 在检测到项目文件发生更改时会提示重新加载。

作为最后一个想法,我考虑过在 CompileNone 之间操作 BuildAction 属性,但这听起来我的扩展程序要正确维护它可能需要做很多工作,使其与每个例如,用户在 IDE 中切换配置的时间。

有没有人对这种事情有任何经验可以给我任何建议,或者我应该放弃希望并坚持在任何地方手动添加#if指令?

【问题讨论】:

  • 可能的方法是,1)为每个配置单独的项目文件; 2) 一个核心项目,具有基于基本配置的扩展项目。与您现在尝试实现的目标相比,它们更容易管理。
  • 简单地执行#ifs 有一个论据:大多数人都知道它是如何工作的。或者至少比了解 MSBuild 的人多得多。我喜欢 MSBuild 黑客,但我最不想做的就是花一个小时试图弄清楚为什么这个文件没有被编译,只是发现项目文件中有魔法。
  • @JasonMalinowski:有问题的代码是部分类的集合,这些部分位于名为 Class.cs、Class.Client.cs 和 Class.Server.cs 的文件中,所以不是太令人困惑。必须添加所有 #ifs 只是很乏味 - 有很多文件要做和维护。

标签: msbuild visual-studio-extensions vspackage


【解决方案1】:

您可能想探索您提到的 MSBuild 选项。

您实际上不必从文件中加载 MSBuild 项目,因为 Visual Studio 为您提供了一种直接访问 MSBuild 项目的方法,即:

string projectPath = projectItem.ContainingProject.FullName;
MsBuildProject project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(projectPath);
var compileItems = project.GetItems("Compile");

从那里您可以找到您的特定项目并可能添加条件属性,尽管我自己没有尝试过此步骤(如果这不起作用,您可能必须尝试修改 project.Xml 属性下的项目元素而是)。

然后您可以调用project.Save(),这不会触发“重新加载项目?”对话框,因为 MsBuild 项目实例链接到 Visual Studio 项目层次结构的方式。

但是,无论如何,您可能希望强制 Visual Studio 重新加载项目,因为如果您切换构建配置(例如在调试和发布之间),MSBuild 引擎可能不会在构建期间重新评估您的项目条件。可以在此处找到以编程方式执行此操作的代码:

How do I programmatically refresh/reload a VS project after modifying the underlying file?

【讨论】:

  • 谢谢你,我不知道可以在加载时直接访问项目结构。我暂时放弃了尝试,因为我浪费了太多时间并且需要完成一些实际的工作,但我会在下周的某个时候尝试这个建议,并报告它的进展情况。
  • 是的,这是我只有在无法访问或更新 ProjectItem 或 IVsProject.Object 中的属性时才能达到的目标之一。不完全理想,但至少所有项目类型的行为都是一致的(其他两种并不总是如此)。如果您需要更多帮助,请告诉我。
  • 你可以做你想做的事吗?我查到了同样的问题。谢谢
【解决方案2】:

不幸的是,我从来没有时间去坚持创建扩展的最初目标,但我确实使用suggestion by lex-li 实现了我所需要的:每个配置使用单独的项目文件。

由于项目文件都可以驻留在同一目录中,因此只需使用解决方案资源管理器中的“从项目中包含/排除”上下文菜单项即可轻松选择包含哪些文件。这种方式也不需要文件链接,我之前尝试过,发现管理起来非常耗时。

Partial Methods 也值得一看,如果你有类似的需求。它们允许您在一个地方定义方法的签名,但可选地在其他地方实现它。如果不实现,编译器不会生成调用。

关于扩展的最初想法,我怀疑answer by Daniel Nolan 的方向是正确的,但不幸的是我没有去尝试。

【讨论】:

    猜你喜欢
    • 2022-01-25
    • 2011-06-14
    • 1970-01-01
    • 2017-01-06
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    相关资源
    最近更新 更多