我可以使用 roslyn 和新的 .net 项目格式在构建时创建类吗?

Posted

技术标签:

【中文标题】我可以使用 roslyn 和新的 .net 项目格式在构建时创建类吗?【英文标题】:Can I use roslyn and the new .net project format to create classes on build? 【发布时间】:2015-07-22 07:38:06 【问题描述】:

我有一个项目使用新的 .net 项目格式(dnxproject.json,目前使用带有 mono-1.0.0-beta4 的 dnvm,一旦他们得到 dnu restore 工作,最终想使用 coreclr *NIX)。

我在使用 .net/C# 时遇到的一个常见问题是希望在编译时创建代码。例如,我有一个虚拟机,它有一个这样的辅助类:

public static class OpCodes 
    private readonly static IDictionary<byte, OpCode> _opcodes;

    public static OpCode MOV  get; private set; 
    public static OpCode ADD  get; private set; 
    public static OpCode SUB  get; private set; 

    static OpCodes() 
        // OpCode class contains info, e.g., the number of arguments
        MOV = new OpCode(0x00, "MOV", 2);
        ADD = new OpCode(0x01, "ADD", 0);
        SUB = new OpCode(0x02, "SUB", 0);

        _opcodes = new Dictionary<byte, OpCode> 
             MOV.Code, MOV ,
             ADD.Code, ADD ,
             SUB.Code, SUB ,
        ;
    

    public static OpCode Get(byte code) 
        OpCode result;
        if(_opcodes.TryGetValue(code, out result)) 
            return result;
        
        return null;
    

如您所见,那里有很多管道:

    操作码列表 每个操作码的静态 Getter 一种通过二进制值查找 OpCode 的方法

我唯一应该创建的是#1,应用程序的实际内容。应该为我将其包装在字典中并创建静态 getter。

我知道“常规”Visual Studio 有 T4 模板,但这些模板在构建时运行起来很痛苦,而且似乎与 Visual Studio 绑定在一起,因此不再适用。

有什么我可以做的吗?我想我可以在 project.json 中创建自定义操作(例如,dnx . regenopcodes)但我不知道我会在这里运行什么,因为我需要调用 Roslyn,找到 OpCodes 列表(也许做一个抽象 @987654327 @class),解析它,并为我生成具体的OpCodes 类。

或者,我可以创建一个 opcodes.xml 文件并使用普通文本解析从中创建一个 .cs,但我不确定在任何时候我如何配置它dnx . run 它首先运行我的生成器并然后做它通常做的任何事情。

【问题讨论】:

但是在哪里指定了那些必需的操作码? @Tigran 无论在哪里最容易让它们进入构建 :) 例如,internal abstract class OpCodeDefs private readonly OpCode[] OpCodes = new [] new OpCode(0x00, "MOV", 2) 或在外部文件 (opcodes.xml) 中,或者实际上,任何对构建有用的东西。应用程序代码将专门使用生成的类,并且永远不需要知道源代码。 所以Dyamic 不是一个选项(通过解析“源”来构造真实对象),因为您需要类型安全。正确的 ?换句话说,您必须拥有static 方法(比如说)。 @Tigran 嗯...好点。动态可以工作,但这意味着放弃 IntelliSense 和运行时惩罚(过早的优化警报)。绝对是一种选择。 如果你正在转向代码生成,无论如何你都会失去智能感知。但是在代码生成的情况下,您可能会从编译时类型检查中受益,这是不可低估的,并且有点遗憾地忽略它,当我们仍然处于静态类型语言的舒适边界时,如 C# 【参考方案1】:

您可以添加预编译步骤,类似于 Razor 预编译视图的操作:https://github.com/aspnet/Mvc/blob/64e726d2b26422c5452475627e4afaba307edec3/src/Microsoft.AspNet.Mvc/RazorPreCompileModule.cs

这是另一个例子:https://github.com/aspnet/dnx/blob/e937e25ab3453ea86bda13c1297c41011dfda9de/ext/compiler/preprocess/Internalization.cs

这就是你连接它的方式https://github.com/aspnet/dnx/blob/3d20719b0a985b6960a3f87d9f5f9b6c3f71b7bc/src/Microsoft.Framework.Runtime/project.json#L16-L18

【讨论】:

谢谢,就这样!目前,这些包在主要 NuGet 提要中仍称为 .Interfaces,但我认为它们很快会重命名为 .Abstractions。 这个答案还有意义吗?看起来ICompileModule 已经消失了。 不再。 ICompileModule 不见了 我如何使用通过语法生成器生成的 c# 类在运行时通过 roslyn 将它们转储到 dll 中?

以上是关于我可以使用 roslyn 和新的 .net 项目格式在构建时创建类吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 2013 中使用 Roslyn 编译器

Roslyn Source Generator 未在 .net 框架 4.7.2 中生成任何源

Ext.net 行编辑旧值和新值

使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题

.NET CoreCLR、CoreRT、Roslyn 和 LLILC 有啥区别

c#7元组不起作用(roslyn编译器异常)