Protobuf-Net не работает на Monodroid с InvalidOperationException в режиме выпуска - PullRequest
3 голосов
/ 28 февраля 2012

При создании приложения Monodroid мы использовали Protobuf-net для сериализации. Он работает в режиме отладки, когда включена быстрая отладка, однако после переключения в режим выпуска происходит сбой со следующим исключением:

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, и он работает в режиме отладки. Так что я знаю, что тот тип, который мы пытаемся сериализовать, имеет метод доступа get, и он работает.

Насколько я могу судить, быстрое развертывание изменяет один параметр, называемый "встраивать сборки в APK", при значении false (режим быстрого развертывания) все работает.

Кто-нибудь сталкивался с этой проблемой, есть обходные пути?

РЕДАКТИРОВАТЬ:

Наш файл .proto:

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;
}

1 Ответ

2 голосов
/ 01 марта 2012

(Управляемый) компоновщик, используемый в Mono для Android, удалит неиспользуемый код для создания небольших приложений. Этот процесс удаления (и выбор) основан на статическом анализе, и он не найдет вещи, которые используются только отражением.

Попробуйте настроить параметры для отключения компоновщика , т. Е. Установите для него значение "Не связывать" и повторите попытку. Если это работает, то это, вероятно, проблема.

Если это так, вы можете либо указать компоновщику игнорировать сборку, где находится свойство (параметр командной строки должен называться --linkskip), либо добавить атрибут [Preserve] в свойстве (или ввести ) указать компоновщику не удалять код (даже если он выглядит неиспользованным).

...