编译时 – C# 元编程,通过编译时代码生成和求值实现。
Comptime – C# meta-programming with compile-time code generation and evaluation

原始链接: https://github.com/sebastienros/comptime

## Comptime:C# 编译时代码生成 Comptime 是一个 .NET 源代码生成器,它将计算从运行时转移到编译时,从而提高应用程序性能。开发者可以通过 `[Comptime]` 属性标记方法,在编译期间执行代码并将结果直接序列化为 C# 源代码。这消除了在构建时已知值的运行时冗余计算。 Comptime 支持各种返回类型,包括基本类型、`IReadOnlyList/Dictionary` 和 `List/Dictionary`。参数必须是编译时常量——字面量、字面量表达式或集合初始化器。它利用 C# 拦截器无缝地将方法调用替换为预计算值。 **主要优点:** 更快的启动和执行速度,通过将工作卸载到构建时来提高性能。 **要求:** .NET 8.0+,C# 12+(用于拦截器)。通过 NuGet 包安装:``。该工具会强制执行规则,例如部分类中的静态方法和不可变返回类型(避免使用数组而倾向于 `IReadOnlyList`)。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 Comptime – C# 元编程,编译时代码生成和评估 (github.com/sebastienros) 25 分,bj-rn 发表于 2 小时前 | 隐藏 | 过去 | 收藏 | 1 条评论 mfro 发表于 3 分钟前 [–] 这看起来像是应该内置到 MSBuild 中的功能。回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

A .NET source generator that executes methods at compile time and serializes their results to C# code. Comptime brings meta-programming capabilities to C#, enabling compile-time code generation and evaluation.

Comptime allows you to mark methods with the [Comptime] attribute to have them executed during compilation. The return values are serialized into C# source code and used at runtime, eliminating the need for runtime computation of values that can be determined at build time.

This meta-programming approach enables developers to shift expensive computations from runtime to compile time, resulting in faster application startup and execution.

  • Compile-time execution: Methods marked with [Comptime] are executed during compilation
  • Method parameters: Methods can accept parameters with compile-time constant expressions
  • C# serialization: Results are serialized to valid C# code
  • Supported return types:
    • Primitive types: int, long, short, byte, sbyte, uint, ulong, ushort, float, double, decimal, bool, char, string
    • Collections: IReadOnlyList<T>, IReadOnlyDictionary<TKey, TValue>, List<T>, Dictionary<TKey, TValue>
    • Note: Arrays are not allowed as return types because they are mutable. Use IReadOnlyList<T> instead.
  • Supported argument types: Any expression that doesn't contain variables, including:
    • Literals: 42, "hello", true
    • Collection initializers: new List<int> { 1, 2, 3 }, new[] { "a", "b", "c" }
    • Expressions: 1 + 2, Math.PI * 2
    • Const values and enum members
  • Interceptor-based: Uses C# interceptors to replace method calls with pre-computed values

Basic Usage (Parameterless Methods)

using Comptime;

public static partial class Constants
{
    [Comptime]
    public static IReadOnlyList<int> GetPrimeNumbers()
    {
        // Complex computation that runs at compile time
        var primes = new List<int>();
        for (int i = 2; i <= 100; i++)
        {
            if (IsPrime(i))
                primes.Add(i);
        }
        return primes;
    }
    
    private static bool IsPrime(int n) { /* ... */ }
}

// At runtime, calling GetPrimeNumbers() returns the pre-computed list
var primes = Constants.GetPrimeNumbers(); // Returns [2, 3, 5, 7, 11, ...]
using Comptime;

public static partial class Math
{
    [Comptime]
    public static long Factorial(int n)
    {
        if (n <= 1) return 1;
        long result = 1;
        for (int i = 2; i <= n; i++)
            result *= i;
        return result;
    }

    [Comptime]
    public static int SumList(IReadOnlyList<int> numbers)
    {
        return numbers.Sum();
    }
}

// Each unique argument combination is computed at compile time
var fact5 = Math.Factorial(5);   // Pre-computed: 120
var fact10 = Math.Factorial(10); // Pre-computed: 3628800

// Collection initializers work too!
var sum = Math.SumList(new List<int> { 1, 2, 3, 4, 5 }); // Pre-computed: 15
var sum2 = Math.SumList(new[] { 10, 20, 30 });           // Pre-computed: 60
using Comptime;

public static partial class Utils
{
    [Comptime]
    public static int CountItems<T>(IReadOnlyList<T> items)
    {
        return items.Count;
    }

    [Comptime]
    public static string JoinStrings(IReadOnlyList<string> strings, string separator)
    {
        return string.Join(separator, strings);
    }
}

var count = Utils.CountItems(new[] { "a", "b", "c" }); // Pre-computed: 3
var joined = Utils.JoinStrings(new[] { "hello", "world" }, " "); // Pre-computed: "hello world"
  • .NET 8.0 or later
  • C# 12 or later (for interceptors support)
<PackageReference Include="Comptime" Version="1.0.0" />
  1. The source generator finds methods marked with [Comptime]
  2. It identifies all call sites and their arguments
  3. For each unique argument combination, it executes the method at compile time
  4. The return values are serialized to C# literals/expressions
  5. Interceptor methods are generated that return the pre-computed values
  6. At runtime, calls to the original methods are intercepted and return the cached values
Code Description
COMPTIME001 Class must be partial
COMPTIME002 Method must be static
COMPTIME004 Unsupported return type
COMPTIME005 Compilation emit failed
COMPTIME006 Method execution failed
COMPTIME007 Serialization failed
COMPTIME011 Array return type not allowed (use IReadOnlyList)
COMPTIME012 Argument must be a constant (no variables allowed)
  • Methods must be static
  • The containing class must be partial
  • Return types must be immutable (arrays are not allowed, use IReadOnlyList<T>)
  • Method arguments must be compile-time constant expressions (no variables, only literals and expressions of literals)
  • Methods cannot have side effects that depend on runtime state

MIT License

联系我们 contact @ memedata.com