2012-02-28 8 views
3

Monodroidアプリケーションを構築する我々は、直列化のためにProtobuf-netを使用してきた。Protobuf-NetはMonodroidでリリースモードのInvalidOperationExceptionで失敗する

ex {System.InvalidOperationException: Cannot serialize property without a get accessor 
at ProtoBuf.Serializers.PropertyDecorator.SanityCheck (System.Reflection.PropertyInfo property, IProtoSerializer tail, System.Boolean& writeValue, Boolean nonPublic) [0x00000] in <filename unknown>:0 
at ProtoBuf.Serializers.PropertyDecorator..ctor (System.Type forType, System.Reflection.PropertyInfo property, IProtoSerializer tail) [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.ValueMember.BuildSerializer() [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.ValueMember.get_Serializer() [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.MetaType.BuildSerializer() [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.MetaType.get_Serializer() [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.RuntimeTypeModel.Serialize (Int32 key, System.Object value, ProtoBuf.ProtoWriter dest) [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.TypeModel.SerializeCore (ProtoBuf.ProtoWriter writer, System.Object value) [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.TypeModel.Serialize (System.IO.Stream dest, System.Object value, ProtoBuf.SerializationContext context) [0x00000] in <filename unknown>:0 
at ProtoBuf.Meta.TypeModel.Serialize (System.IO.Stream dest, System.Object value) [0x00000] in <filename unknown>:0 
at ProtoBuf.Serializer.Serialize[UltraliteJCommandParameters] (System.IO.Stream destination, Company.Product.ProtocolBuffers.Android.UltraliteJCommandParameters instance) [0x00000] in <filename unknown>:0 
at Company.Product.UltraliteJ.DataCommand.SerializeParameters() [0x00261] in C:\DevSVN\Product\FS\Trunk\FSAndroidSolution\Company.Product.UltraliteJ\DataCommand.cs:109 
at Company.Product.UltraliteJ.DataCommand.LoadValue() [0x00001] in C:\DevSVN\Product\FS\Trunk\FSAndroidSolution\Company.Product.UltraliteJ\DataCommand.cs:44 
at Company.Product.Ultralite.Controlers.UltraliteDataServer.RunUpgradeScripts (System.String version, Boolean syncSuccessful) [0x0007e] in C:\DevSVN\Product\FS\Trunk\Company.Product.Ultralite.Controlers\UltraliteDataServer.cs:375 } System.InvalidOperationException 

我々は.protoファイルから生成されたコードを使用している、そしてそれは、デバッグで動作します:速いdeplyは、我々はそれが次の例外で失敗モードを解除するために切り替えるしかし一度、オンになっているとき、それはデバッグモードで動作しますモード。だから、私たちがシリアライズしようとしているのは、アクセサーを取得し、それが動作することを知っています。

私が知っている限り、「APKに組み込みアセンブリ」と呼ばれる単一の設定を変更すると、false(高速展開モード)に設定するとすべてが機能します。

誰かがこの問題に遭遇しましたが、回避策はありますか?

EDIT:

当社の.protoファイル:障害がoccuringた

package Company.ProductName.ProtocolBuffers.Android; 

option java_package = "com.company.productname.protocolbuffers.android"; 
option java_outer_classname = "AndroidParametersProto"; 

message UltraliteJCommandParameters { 
    required string command_text = 1; 
    repeated UltraliteJCommandParameter parameters = 2; 
} 

message UltraliteJCommandParameter { 
    required string field_name = 1; 
    required string data_type = 2; 
    required bool is_null = 3; 
    optional double double_value = 4; 
    optional float float_value = 5; 
    optional int32 int32_value = 6; 
    optional int64 int64_value = 7; 
    optional uint32 uint32_value = 8; 
    optional uint64 uint64_value = 9; 
    optional sint32 sint32_value = 10; 
    optional sint64 sint64_value = 11; 
    optional fixed32 fixed32_value = 12; 
    optional fixed64 fixed64_value = 13; 
    optional sfixed32 sfixed32_value = 14; 
    optional sfixed64 sfixed64_value = 15; 
    optional bool bool_value = 16; 
    optional string string_value = 17; 
     optional bytes bytes_value = 18; 
} 

コード:

private byte[] SerializeParameters() 
{ 
    byte[] paramBytes; 

    Company.Product.ProtocolBuffers.Android.UltraliteJCommandParameters parameters = new Product.ProtocolBuffers.Android.UltraliteJCommandParameters(); 
    Company.Product.ProtocolBuffers.Android.UltraliteJCommandParameter parameter; 

    parameters.command_text = CommandText; 

    foreach (DataParameter param in Parameters) 
    { 

     parameter = new Product.ProtocolBuffers.Android.UltraliteJCommandParameter(); 
     parameter.field_name = param.Name; 

     if (param.Value == null || param.Value == (object)DBNull.Value) 
     { 
      parameter.is_null = true; 
     } 
     else 
     { 

      parameter.is_null = false; 
      parameter.data_type = param.Value.GetType().ToString().Replace("System.", string.Empty); 

      switch (param.Value.GetType().ToString()) 
      { 
       case "System.String": 
        parameter.string_value = (string)param.Value; 
        break; 
       case "System.Int32": 
        parameter.sint32_value = (int)param.Value; 
        break; 
       case "System.Int64": 
        parameter.sint64_value = (long)param.Value; 
        break; 
       case "System.Boolean": 
        parameter.bool_value = (bool)param.Value; 
        break; 
       case "System.DateTime": 
        parameter.double_value = (((DateTime)param.Value).ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime()).TotalMilliseconds; 
        break; 
       case "System.Single": 
        parameter.float_value = (float)param.Value; 
        break; 
       case "System.Double": 
        parameter.double_value = (double)param.Value; 
        break; 
      } 
     } 

     parameters.parameters.Add(parameter); 

    } 

    using (MemoryStream stream = new MemoryStream()) 
    { 
     Serializer.Serialize<Company.Product.ProtocolBuffers.Android.UltraliteJCommandParameters>(stream, parameters); 
     paramBytes = stream.ToArray(); 
    } 

    return paramBytes; 
} 
+0

こんにちは。私はprotobuf-netの作者です。それが起こると私はMono for Androidを利用できます。私は非常に基本的な例を使ってKindle Fireでここでレプロを試しましたが、デバッグ(高速デプロイメントの有無にかかわらず)とリリース(高速デプロイメントは利用できません)の両方で完全に機能します。私は捜査を手伝ってうれしいですが、私は再製作に使うことができるものはありますか? –

+0

もう一つの疑問は... Monoコンパイラが、明らかに使われていないアクセッサを最適化していると思っています。私はそれが有用な場合、エラーメッセージに型/メンバ名を追加することができますか? –

+0

@MarcGravellお返事ありがとうございます。問題は大規模なプロジェクトであり、同じ構造の小さなソリューションで問題を再現しようとしていますので、具体的なものをお届けできます。 – dmck

答えて

2

のAndroid用モノラルで使用(管理)リンカは削除されます未使用小さなアプリケーションを作成するコードはです。この除去プロセス(および選択)は静的解析に基づいており、リフレクションでのみ使用されるものは検出されません。

リンカーを無効にするオプションを設定してください。「リンクしない」に設定してもう一度やり直してください。それがうまくいくなら、これはおそらく問題です。

それは、プロパティが存在しますが、アセンブリを無視するようにリンカーに伝えることができるのいずれか(コマンドラインオプションを--linkskip名前を付ける必要があります)、またはあなたがあなたの財産(またはタイプ)に[Preserve]属性を追加することができます伝えるためにケースの場合リンカーはコードを削除しないでください(が未使用の場合はとなります)。

+0

ああ、昨日の私のコメント「私が疑問に思っているもう一つのことは、Monoコンパイラが、明らかに「使われていない」アクセサーを最適化しているということです。 –

+0

@MarcGravellかなり閉鎖:)ちょうど次の(オプション)ビルドパイプラインのステップダウン。 – poupou

+0

@poupou [Preserve]属性で作業しましたが、すべてのプロパティに追加する必要がありました。提案していただきありがとうございます! – dmck