自定义MSBuild任务依赖于编译的代码,但也生成依赖的代码

时间:2011-08-21 05:25:42

标签: c# msbuild

我正在尝试生成一个C#代码文件,该文件基于XML文件构造对象树。 XML中的元素指的是正在编译的项目中定义的类型。生成的代码需要构建在正在编译的项目中找到的类型的对象树。更复杂的是,生成的代码需要编译到正在编译的项目中,并由当前正在编译的项目中的代码引用。

我目前正在尝试使用自定义MSBuild任务执行此操作。此任务将分发给其他开发人员以用于他们自己的项目,因此我无法将可用的类型硬编码到任务中。

以下是一些示例代码,用于说明我正在做的事情:

// This is not generated
public class SomeClass {

    public void DoSomething() {}

    public string SomeProperty { get; set; }
}

SomeClass 是在项目中的非生成代码中定义的Type。以下是引用 SomeClass 的XML文件,并填充 SomeProperty 属性:

... bunch of XML...
<SomeClass SomeProperty="SomeValue" />
... bunch more XML...

SomeOtherClass 有一个非生成的部分声明:

// This is not generated
public partial class SomeOtherClass {

    public void SomeMethod() {
        someField.DoSomething();
    }
}

任务创建部分 SomeOtherClass 声明:

// This is generated
public partial class SomeOtherClass {

    private SomeClass someField = new SomeClass() {
        SomeProperty = "SomeValue"
    };
}

我认为这看起来很像WPF必须为XAML文件做的事情,并且我的用法是相关的(使用XML生成实例化对象树的代码,基于正在编译的同一项目中的类型)。

解决这个问题的最佳方法是什么?我应该在Task中进行多阶段编译和使用中间文件吗?我是否应该尝试在没有生成代码的情况下在Task中单独构建临时程序集,然后对临时程序集进行反射,然后生成代码文件,然后允许正常构建过程继续?

1 个答案:

答案 0 :(得分:5)

问题太模糊,无法确定这有用,但希望这会有所帮助。

1。正确获取.props和.targets文件

  1. 配置LoadTimeSensitiveTargetsLoadTimeSensitiveProperties以确保IntelliSense在项目构建之前仍然有效。
    https://github.com/antlr/antlrcs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/AntlrBuildTask/Antlr3.targets#L36-L45

  2. 使用AvailableItemName属性可确保用户可以将XML文件的构建操作设置为自定义项目类型。
    https://github.com/antlr/antlrcs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/AntlrBuildTask/Antlr3.targets#L75-L79

  3. 如有必要,使用ItemDefinitionGroup元素为具有此自定义项类型的对象定义默认属性,以减少用户为配置XML文件的构建所需的工作量。
    https://github.com/antlr/antlrcs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/AntlrBuildTask/Antlr3.targets#L81-L88

  4. 非常非常密切关注项目添加到_GeneratedCodeFiles等集合的方式,以确保清洁目标正确清理您的构建。

  5. 使用 .props 文件指定默认配置元素。当您创建用于分发的NuGet包时, .props 文件将包含在用户项目的顶部,而 .targets 将被列入项目的底部。

  6. 2。在代码生成期间不要执行不必要的验证

    如果用户犯了错误(例如,引用项目中不存在的项目),C#编译器将通知您。通过在代码生成步骤中避免这种分析,避免了问题中描述的循环依赖。

    3。禁用或卸载ReSharper

    ReSharper不支持在构建期间生成代码的扩展。尽管上述指令具体遵循XAML支持多年来建立的模式,但您仍将坚持以下选择:

    1. 保留ReSharper,但没有为生成的代码提供IntelliSense支持。
    2. 卸载ReSharper,让Visual Studio为您的自定义项目类型提供与XAML文件相同的清洁IntelliSense体验,从您打开解决方案的第一刻开始。
    3. 4。实例

      以下是在构建期间生成代码的两个扩展。

      ANTLR 3:
      https://github.com/antlr/antlrcs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/AntlrBuildTask/Antlr3.props https://github.com/antlr/antlrcs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/AntlrBuildTask/Antlr3.targets

      ANTLR 4:
      https://github.com/tunnelvisionlabs/antlr4cs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/runtime/CSharp/Antlr4BuildTasks/Antlr4.v4.0.props https://github.com/tunnelvisionlabs/antlr4cs/blob/9ee43ed9486e55afcc1db06f9f0755658974f99f/runtime/CSharp/Antlr4BuildTasks/Antlr4.v4.0.targets