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#中,用什么来表示上面例子中的结构是最好的原语,假设用对象来表示它们会很好?使用不安全子句复制类似c的定义,然后在每个结构周围使用类包装
使用StructLayout属性来指导托管结构内部的布局,并为每个这样的结构使用wrapper类
使用完整的类,只使用内存或网络流进行有线表示
除了托管c++,还有其他想法吗?
其次,很明显,任务本身是非常劳动密集型的,在任何情况下都容易出错。是否有任何自动化来帮助将C头转换为上述解决方案之一?有谁能推荐一个吗?
乌利希期刊指南。
用图画来更好地描述问题。
(BoxA)——在TCP/IP上运行的有线协议——(BoxB)
假设BoxA运行一些纯C代码,BoxB应该运行c#代码。
有线协议代表了这个巨大的规范,有100多个结构来通信BoxA和BoxB。如果协议是用Google协议缓冲区或Apache Thrift定义的,可能会容易得多,但不幸的是,我处理的是标准定义。
我认为最好按照如下方式手动转换它们:
[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原则。
同样,基于您的领域模型,您当然可以利用抽象、继承等等。
哦。保持简单和直观。