【发布时间】:2018-03-10 23:16:41
【问题描述】:
我开发了一个供内部使用的代码生成器,其中代码资产 (POCO) 是基于 C# 接口生成的。代码生成过程以编程方式将项目添加/删除到 csproj 文件。工作流程如下:开发人员在 Visual Studio 2017 中添加新的 C# 接口,或删除现有的 C# 接口。如果开发人员先保存项目文件,然后运行代码生成器,则一切正常。将代码生成的资产添加到项目中(或删除),Visual Studio 会相应地反映这些更改。但是,如果开发人员在运行代码生成器之前未能保存 csproj 文件,并且删除了 C# 接口,则代码生成的资产不会从项目中删除,因为 Visual Studio 不接受 csproj 文件修改。
在代码生成器中,我物理上删除了对已删除的代码生成文件的引用,并保存了 csproj 文件。我通过在记事本中打开 csproj 来验证引用的文件是否已从 csproj 文件中删除。但是,只要我将 Visual Studio 放在焦点上,Visual Studio 就会识别出 csproj 文件已更改,并询问我是否要丢弃、覆盖、另存为等,并且在我的代码生成过程中对 csproj 文件所做的更改会丢失。 Visual Studio 将对已删除文件的引用添加回 csproj 文件。我尝试过丢弃、覆盖、另存为等,但我没有让 Visual Studio 接受新修改的 csproj 文件(其中删除了对已删除文件的引用)。
这是我删除代码生成资产的代码:
using Microsoft.Build.Evaluation;
using Microsoft.Build.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
public static void RemoveGeneratedFilesFromProject(String projectPath)
{
UnloadAnyProject();
var project = ProjectCollection.GlobalProjectCollection.LoadedProjects.FirstOrDefault(pr => pr.FullPath == projectPath);
//ATTEMPT TO SAVE PROJECT IN CASE DEVELOPER DID NOT...
project.Save();
//GET A LIST OF ITEMS CONTAINING PATH TO CODE-GENERATED ASSETS ("Generated\API")
IList<ProjectItem> generatedItemsList = project.GetItems("Compile").Where(item => item.EvaluatedInclude.Contains(@"Generated\Api")).ToList();
foreach (var item in generatedItemsList)
{
project.RemoveItem(item);
}
//SAVE PROJECT TO REFLECT ALL OF THE CODE GENERATED ITEMS REMOVED FROM PROJECT FILE
project.Save();
UnloadAnyProject();
}
private static void UnloadAnyProject()
{
ProjectCollection projcoll = ProjectCollection.GlobalProjectCollection;
foreach (Project project in projcoll.LoadedProjects)
{
ProjectCollection mypcollection = project.ProjectCollection;
mypcollection.UnloadProject(project);
}
}
是否可以让 Visual Studio 只接受新的 csproj 文件?删除资产时,我需要对 csproj 文件进行一些设置吗?让 Visual Studio 对修改后的 csproj 文件犹豫不决,这会妨碍代码生成器在删除不再需要的代码生成资产(源于物理删除 C# 接口文件)方面的有用性。
编辑
这是一个视频,展示了在 Visual Studio 中运行 T4 生成器的过程,该生成器基于 C# 接口生成 C# 资产。我删除了源 C# 接口,重新运行代码生成器,项目文件相应更新,导致项目重新加载。
https://www.screencast.com/t/JWTE0LpkXZGX
问题不在于项目被重新加载。问题是代码生成器更新并将 csproj 文件保存在 Visual Studio 之外,这会导致 Visual Studio 由于 csproj 文件更改而感到困惑。如何让 Visual Studio “静默”地接受保存到 csproj 文件的更改?
感谢您的帮助。
【问题讨论】:
-
您是在构建期间还是在构建过程之外从 msbuild 目标运行代码生成器作为独立的 exe / 工具?大多数生成方法都集成到 msbuild 中,因此即使在 VS 中的设计时构建期间,它们也可以动态添加代码,而无需编辑项目文件
-
所以基本上第一次调用 project.Save() 在 VS 中没有效果?
-
这是一个用 T4 文件编写的独立代码生成器。我不确定如何将 T4 与 MS Build 集成。第一个 project.save() 似乎不影响视觉工作室。第二次保存是在删除过时的代码资产后发生的,并且 VS 会被提示重新加载。但似乎 VS 在内存中有自己的项目版本,这与在代码生成器范围内加载/修改/保存的 csproj 文件不同。
-
这是一段代码生成器在 VS 中运行的视频。你会看到,当我删除一个 C# 接口而不保存项目时,VS 意识到 DataContracts 项目的 csproj 文件已更改。系统会提示用户丢弃、另存为、覆盖等。选择“另存为”不会从 VS 中删除已删除的资产。引用仍然存在于 csproj 文件中。 screencast.com/t/JWTE0LpkXZGX
-
@MartinUllrich - 我正在通过 TextTransform 生成文件的内容,并使用 System.IO.File 将文件物理写入路径。这就是为什么我必须手动修改 csproj 文件以便它知道新文件的原因。你是说我可以在我的 T4 中引用 Microsoft.Build 程序集并使用 Microsoft.Build 添加新生成的文件?
标签: c# msbuild visual-studio-2017 microsoft.build