C# 源代码生成器:为调用同一方法生成不同的代码

问题描述 投票:0回答:1

我将用一个具体的例子来介绍我的问题。 实际问题位于本文底部。

简介

我想从给定的字节数组中提取一些未对齐的数据

  • 起始位位置
  • 位数
  • 数据是MSB优先(大端)还是LSB优先(小端)格式

为此,我创建了一个提供静态方法的

Bitpacker

  ulong ReadRaw(byte[] src, int startBit, int bitLength, Endianness endianness = Endianness.LSB_FIRST)

这种方法当然必须进行一些计算,以使用循环等方式从字节中获取所需的位,这很慢。我需要每秒评估数千次数据。

因为参数是编译时已知的常量,我可以通过手动查找要提取的位以及如何移动它们来硬编码快速变体。

例如以下两个对

raw
的分配执行相同的操作:

ulong raw;

// Manually extract bits
raw = ((ulong)(src[5] & 0xFC) >> 2) + ((ulong)(src[6] & 0x3) << 6);

// Use the slow generic implementation
raw = Bitpacker.ReadRaw(src,42,8, Endianness.LSB_FIRST);

硬编码当然会使编写正确的代码变得困难,并显着降低代码的可维护性。这就是我认为源生成器可以发挥作用的地方。

实际问题

是否可以使用源生成器功能根据常量参数为每次调用

ReadRaw
生成不同的代码,或者是否可以使用源生成器完全替换对
ReadRaw
的调用?

c# sourcegenerators bit-packing
1个回答
0
投票

我之前通过在生成的方法中使用 CallerFilePath 和 CallerLineNumber 属性做了类似的事情。

源生成器在生成代码时也可以访问这些值。因此,您可以在文件/行号和要执行的代码之间创建映射。

字典对我有用,但 if 语句对于你的情况可能会更好。

您生成的方法将类似于:

public void ReadRaw(byte[] src, int startBit, int bitLength, Endianness endianness = Endianness.LSB_FIRST, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
    if (sourceFilePath == "..." && sourceLineNumber == ...)
    {
        return  ((ulong)(src[5] & 0xFC) >> 2) + ((ulong)(src[6] & 0x3) << 6);
    }
}

您可能希望分析器在使用非常量值时发出警告。

© www.soinside.com 2019 - 2024. All rights reserved.