c#中构造类/结构的最佳方法

本文关键字:结构 最佳 方法 | 更新日期: 2023-09-27 17:53:16

我一直在研究以C语言实现为目标的网络协议规范,并分别以C风格定义,如:

struct some_header {
  uint8_t version;
  uint8_t type;
  uint16_t length;
  uint32_t id; /
};
struct some_struct {
  struct some_header header;
  uint8_t field1; 
  uint8_t pad[3]; /* Pad to 32 bits */
  uint32_t field2;
};

规范中定义了大约100个类似"some_struct"的结构。

现在的目标是在c#中复制这些定义,并围绕这些结构增加一些功能。

在c#中,用什么来表示上面例子中的结构是最好的原语,假设用对象来表示它们会很好?
  1. 使用不安全子句复制类似c的定义,然后在每个结构周围使用类包装

  2. 使用StructLayout属性来指导托管结构内部的布局,并为每个这样的结构使用wrapper类

  3. 使用完整的类,只使用内存或网络流进行有线表示

除了托管c++,还有其他想法吗?

其次,很明显,任务本身是非常劳动密集型的,在任何情况下都容易出错。是否有任何自动化来帮助将C头转换为上述解决方案之一?有谁能推荐一个吗?

乌利希期刊指南。

用图画来更好地描述问题。

(BoxA)——在TCP/IP上运行的有线协议——(BoxB)

假设BoxA运行一些纯C代码,BoxB应该运行c#代码。

有线协议代表了这个巨大的规范,有100多个结构来通信BoxA和BoxB。如果协议是用Google协议缓冲区或Apache Thrift定义的,可能会容易得多,但不幸的是,我处理的是标准定义。

c#中构造类/结构的最佳方法

我认为最好按照如下方式手动转换它们:

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct Header
{
    public Byte version;
    public Byte type;
    public UInt16 length;
    public UInt32 id;
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct Struct
{
    public Header header;
    public Byte field1;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    public Byte[] pad;
    public UInt32 field2;
}

将来你可能需要将它们与本地函数一起使用…所以最好将它们作为结构体,并直接在。net代码中使用它们。如果你必须将它们作为本地方法的参数传递,或者将结果IntPtrs转换回它们(Marshal.PtrToStructure),它们将非常有用。

是否有任何自动化来帮助将C头转换为上述解决方案之一?

使用C预处理器获得一个大文件,然后使用脚本切割结构体定义,然后应用搜索&替换为转换类型和添加属性。

我倾向于使用封装字节数组引用和索引的类型,然后有方法从中读取或写入下一个字节/字/长字/任何内容。将字节流转换为结构类型的代码如下所示:

myReader = new ByteArrayReader(myArr);
myHead.version = myReader.getByte();
myHead.type; = myReader.getByte();
myHead.length = myReader.getUInt16();
myHead.id = myReader.getUInt32();

在这种情况下,我假设myHead将是具有上述公共字段的透明结构。我不建议将头类型作为类,除非实例实际上要"做"一些事情。将读取器类型设置为结构可能会提高性能,但在某些情况下可能会导致令人惊讶的语义。框架中最接近的等价是List<T>.Enumerator,它是出于性能考虑的结构体。

关于自动化问题,我刚刚发现了一个优秀的工具,可以从c-header

生成PInvoke样式的代码

http://clrinterop.codeplex.com/releases/view/14120 ReviewsAnchor

特别是

需要在命令行

使用以下工具

sigimp/lang:cs "path-to-c-header"

生成的代码示例下面:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct some_header {
/// uint8_t->unsigned char
public byte version;
/// uint8_t->unsigned char
public byte type;
/// uint16_t->unsigned int
public uint length;
/// uint32_t->unsigned int
public uint id;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
public some_struct {

public some_header header;
/// uint64_t->unsigned int
public uint xxx;
/// uint32_t->unsigned int
public uint xxx2;
/// uint8_t->unsigned char
public byte xxx3;
/// uint8_t->unsigned char
public byte xxx4;
/// uint8_t[2]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=2)]
public string pad;
/// uint32_t->unsigned int
public uint xxx5;
/// uint32_t->unsigned int
public uint xxx6;
}

虽然c#有Struct,但最好的选择是使用Class。您可以使用类作为数据容器,参见贫血域模态,或者您可以在其中实现,例如验证和业务逻辑。参见:domain driven.

在处理您的领域模型时,请确保采用SOLID原则。

同样,基于您的领域模型,您当然可以利用抽象、继承等等。

哦。保持简单和直观。