6

私は、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;
};

仕様で定義されている「some_struct」のような構造体は約100あります。

ここでの目標は、C#で定義を複製し、それらの構造の周りで機能を拡張することです。

上記の例のような構造をオブジェクトとして表現するのが良いと仮定して、C#で使用するのに最適なプリミティブは何ですか?

  1. 安全でない句を使用してCのような定義を複製してから、すべての構造体のクラスラッパーを使用します

  2. StructLayout属性を使用して、管理対象構造内のレイアウトをガイドし、そのような構造ごとにラッパークラスを使用します

  3. 本格的なクラスを使用し、メモリまたはネットワークストリームを使用したワイヤ表現のみに進みます

マネージC++以外のアイデアはありますか?

第二に、明らかに、タスク自体は非常に労働集約的であり、リストされているいずれの場合でもエラーが発生しやすいです。Cヘッダーを上記のソリューションの1つに変換するのに役立つ自動化はありますか?誰かお勧めしてもらえますか?

UPD。

問題をよりよく説明するためのいくつかの図面。

(BoxA)--- TCP / IP上で実行されるワイヤプロトコル---(BoxB)

BoxAが純粋なCで記述されたコードを実行すると仮定すると、BoxBはC#で記述されたコードを実行する必要があります。

そして、ワイヤープロトコルは、BoxAとBoxBを通信するための100以上の構造を持つこの巨大な仕様を表しています。プロトコルがGoogleProtocolBuffersまたはApacheThriftで定義されていれば、はるかに簡単だったかもしれませんが、残念ながら、私はそのまま定義された標準を扱っています。

4

5 に答える 5

4

私見では、次のように手動で変換することをお勧めします。

[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 コードで直接使用することをお勧めします。これらは、ネイティブ メソッドのパラメーターとして渡す必要がある場合、または結果の IntPtr をそれらに戻す必要がある場合 ( Marshal.PtrToStructure ) に非常に役立ちます。

于 2013-01-15T18:31:52.687 に答える
1

Cヘッダーを上記のソリューションの1つに変換するのに役立つ自動化はありますか?

C プリプロセッサを使用して 1 つの大きなファイルを取得し、スクリプトを使用して構造体定義を切り取り、検索と置換を適用して型を変換し、属性を追加します。

于 2013-01-15T18:42:02.970 に答える
0

私の傾向は、バイト配列参照とインデックスをカプセル化する型を使用し、それから次のバイト/ワード/ロングワード/何でも読み書きするメソッドを持つことです。バイトストリームから構造体タイプに変換するコードは、次のようになります。

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

この場合、myHead上記のパブリックフィールドを持つ透過的な構造であると想定しています。インスタンスが実際に何かを「実行」しない限り、ヘッダータイプをクラスにすることはお勧めしません。リーダータイプを構造にすることでパフォーマンスが向上する可能性がありますが、場合によっては驚くべきセマンティクスが発生する可能性があります。フレームワークで最も近いものは、ですList<T>.Enumerator。これは、パフォーマンス上の理由から構造体です。

于 2013-01-15T20:36:28.503 に答える
0

自動化の質問に関しては、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;
}
于 2013-01-16T20:56:46.393 に答える
-2

C# には がStructありますが、最善の策は を使用することClassです。クラスをデータ コンテナーとして使用するか、貧血ドメイン モーダルを参照するか、検証やビジネス ロジックなどの実装を内部に含めることができます。参照: ドメイン主導。

ドメイン モデルに取り組んでいる間は、SOLID の原則を必ず取り入れてください。

また、ドメイン モデルに基づいて、確かに抽象化、継承などを利用できます。

おー。シンプルで直感的なものにしてください。

于 2013-01-15T18:30:18.063 に答える