8

.NET にはいくつかの (たくさんの) クラスがありました。protobuf-netを使用してそれらをマークアップし、 Google オリジナル ライブラリを介して C++ コード側の .proto ラッパーを生成しました。

だから私はメッセージを持っています (いくつかの EventBase クラスに C++ DebugString() があります (.NET ではEventCharacterMoved 継承されますEventBaseが、C++ ではオプションのプロパティに書き込むだけです)):

UserId: -2792
EventCharacterMoved {
  Coordinates {
    Position {
      X: 196.41913
      Y: 130
      Z: 213
    }
    Rotation {
      X: 207
      Y: 130
      Z: 213
    }
  }
  OldCoordinates {
    Position {
      X: 196.41913
      Y: 130
      Z: 213
    }
    Rotation {
      X: 207
      Y: 130
      Z: 213
    }
  }
}

(そのような .proto ファイルから)

message Coordinates {
   optional TreeFloat Position = 1;
   optional TreeFloat Rotation = 2;
}
message EventBase {
   optional int32 UserId = 10 [default = 0];
   // the following represent sub-types; at most 1 should have a value
   optional EventCharacterMoved EventCharacterMoved = 15;
}
message EventCharacterMoved {
   optional Coordinates Coordinates = 100;
   optional Coordinates OldCoordinates = 101;
}
message TreeFloat {
   optional float X = 1 [default = 0];
   optional float Y = 2 [default = 0];
   optional float Z = 3 [default = 0];
}

C++ ではこれを送信し、同じメッセージ コンテンツを .NET から送信します。

C++ コードは、C++ でエンコードされたメッセージと .NET でエンコードされたメッセージを解析できます。.NET コードは、.NET メッセージのみを解析できます。

ネットワーク経由で 87 バイトが飛んでいます ( .Net ファイルC++ ファイルのサイズは同じです) が、内容は異なります。

ここに画像の説明を入力

ご覧のとおり、似ていますが同じではありません。このような違いの結果、CPP コードは .NET C# メッセージを読み取ることができますが、.NET は CPP メッセージを読み取ることができません

逆シリアル化のコードでは、次のようになります。

TestProto.exe で、タイプ 'System.InvalidCastException' の未処理の例外が発生しました

追加情報: タイプ 'TestProto.EventBase' のオブジェクトをタイプ 'TestProto.EventCharacterMoved' にキャストできません。

次のようなコードで:

using (var inputStream = File.Open(@"./cpp_in.bin", FileMode.Open, FileAccess.Read)) {
    var ecm = Serializer.Deserialize<EventCharacterMoved>(inputStream);
}

(彼のコメントでjpaが述べたように)オプションを見てみましょうprotoc --decode_raw

ここに画像の説明を入力

これは、私の CPP ラッパーが最新の Google protobuf バージョンを使用しているのに対し、protobuf-net はおそらく古いエンコーディング形式またはこのようなものを使用しているという事実に関連している可能性があります...

では、.NET protobuf に C++ メッセージを読み取らせる方法 (tham が同じ内容をデコードできるようにする方法) を知りたいのですが。

または、少なくとも元の Google protobuf を .NET protobuf と同じ方法でエンコードする方法は?

そして、本当に興味があり、簡単な例を含む圧縮バンドル (C++ および C# コード用の VS 2010 ソリューションが含まれています)を取得したい人のために

4

2 に答える 2

2

編集; これは、r616 以降で修正する必要があります。


ようやくこれを見る機会がありました (遅れて申し訳ありませんが、社会的な季節休暇の要求が介入しました)。私は今何が起こっているのかを理解しています。

基本的に、データは理論的には同一です。これが実際に到達するのは、フィールドの順序付けです。技術的には、フィールドは通常昇順で書き込まれますが、任意の順序で記述できます。protobuf-net に関して。継承を含まない型の場合、順序に関係なく正常に機能します。protobuf 仕様では継承が定義されていないため、protobuf-net は (一定の需要があるため) 継承のサポートを仕様に追加します。実装機能として、最初にサブクラス情報を書き込みます(つまり、サブタイプであるフィールド 15 がフィールド 10 の前に書き込まれます)。現時点では、逆シリアル化中にも期待されます最初にサブタイプ情報。protobuf-net はこのような継承を使用する唯一の実装であるため、継承機能の使用はほとんど protobuf-net から protobuf-net への使用でのみ見られるため、これが誰にも影響を与えることはめったにありません。

あなたの場合、CPP と相互運用するために .proto を使用しています。これは、CPP コードが protobuf-net データを消費できることを意味しますが、逆方向に型キャスト例外が発生する可能性があります (基本的に、最初のデータ フィールドを取得した時点で具象型の構築を開始します)。

めったに問題になることはありませんが、これは修正が必要なものです。今日か明日、これを見てみることができます。

オプション:

  • サブタイプ フィールドが常にどのデータ フィールドよりも低いことを確認してください
  • サブタイプが必要であることがわかっている場合は、Merge API を使用して、目的のタイプの既存の新しいオブジェクトを渡します。これにより、既存のオブジェクトが正しく読み込まれます。
  • 1日か2日待ってください(うまくいけば!)適切な修正のためにビルドr616以降を使用してください
  • 相互運用を使用する場合は、継承 (およびその他の実装固有の機能) を回避します
    • カプセル化を介して、継承なしで同じデータをモデル化できることに注意してください-そしてそれはうまく機能します; ここで問題となるのは具体的な型の作成です
  • CPP サイトからデータを作成するときは、次の 2 つの部分に分けて、不合理な長さ (つまり、これを実際の解決策とは考えていません) にします。
    • 最初にデータだけを書き込んでシリアル化ますEventBase。別のモデルで、データだけでを書き、シリアル化します。これは、必要な順序でそれらを書き込むことをシミュレートします (protobuf ストリームは追加可能です) - きれいではありませんEventCharacterMovedEventBaseTreeFloat
于 2012-12-31T07:52:29.070 に答える
1

これは、http://code.google.com/p/protobuf-net/issues/detail?id=299およびhttp://code.google.com/p/protobuf-net/issuesに記載されている問題とよく似ています。 /detail?id=331はhttp://code.google.com/p/protobuf-net/source/detail?r=595によって修正されたとされています

使用している .NET protobuf のバージョンは、その修正を組み込むのに十分なほど新しいものですか?

于 2012-12-26T22:29:48.370 に答える