Pergunta

Nos exemplos a seguir:

public class RowData
{
    public object[] Values;
}

public class FieldData
{
    public object Value;
}

Estou curioso como quer protobuf-net ou dotnet-protobufs iria lidar com essas classes. Estou mais familiarizado com protobuf-net, então o que eu realmente tenho é:

[ProtoContract]
public class RowData
{
    [ProtoMember(1)]
    public object[] Values;
}
[ProtoContract]
public class FieldData
{
    [ProtoMember(1)]
    public object Value;
}

No entanto eu recebo um erro dizendo "Não codificação de objeto padrão adequado encontrado". Existe uma maneira fácil de tratar essas classes, que não estou apenas ciente de?

Para elaborar mais sobre o caso de uso:

Esta é uma versão reduzida de uma classe de dados usado na comunicação remota. Então, basicamente parece que isso:

FieldData data = new FieldData();
data.Value = 8;

remoteObject.DoSomething(data);

Nota:. Omiti a implementação ISerializable para simplificar, mas é como você esperaria

Foi útil?

Solução

(atualizado)

Direito; percebi isso ... o principal problema no meu exemplo acima foi o valor-getters; eles estavam jogando exceções. Havia também algumas falhas de biblioteca ( agora fixo).

No entanto, a abordagem mais simples é Nullable<T> passe-thru propriedades:

    [ProtoMember(1)]
    private int? ValueInt32
    {
        get { return Get<int>(); }
        set { Value = value; }
    }

etc, com:

    private T? Get<T>() where T : struct
    {
        return (Value != null && Value is T) ? (T?)Value : (T?)null;
    }

Tanto este como a abordagem * especificado ter sido testado, e agora funcionam bem.

Outras dicas

Re protobuf-net, que eu mantenho:

A questão aqui não é de valor tipos (que, muitas vezes, lidar com multa) - é o uso object aberta, o que significa que simplesmente não sabe quais dados que esperar, e, assim como codificação / decodificação-lo.

No momento, eu não consigo pensar em uma maneira fácil / limpa para lidar com isso. Ele vai lidar com uma série de cenários comuns do tipo valor, listas, e qualquer nível de hierarquia com base em contratos (-contrato de dados, proto-contratos, ou alguns xml-esquemas), mas ele precisa de um indício .

Talvez se você pode esclarecer o caso de uso, eu poderia ser capaz de ajudar mais? Por exemplo, o acima não iria trabalhar muito com DataContractSerializer ou XmlSerializer ou ...

Re dotnet-protobufs; Eu realmente não posso comentar, mas eu tenho certeza que seria ainda menos indulgente; que se destina a ser utilizado com classes geradas a partir de um arquivo de .proto, então object seria simplesmente nunca entrar no modelo (Jon: me corrija se eu estiver errado).

Se você deixar mais informações, você poderia gentilmente postar um comentário aqui? Para que eu possa encontrá-lo facilmente ... Alternativamente, mande-me um e-mail directamente (ver meu perfil SO).


Editar - aqui está a coisa hacky eu tinha em mente - ele não está funcionando no momento, mas vou descobrir por que amanhã (provavelmente). Note-se que, em teoria, os membros extras poderiam ser privado - Estou apenas tentando tornar mais fácil durante a depuração. Note que isso não leva qualquer armazenamento extra. Como eu disse, ele não funciona hoje, mas deve - Vou descobrir o porquê ...

[ProtoContract]
public class FieldData
{
    public object Value {get;set;}

    [ProtoMember(1)]
    public int ValueInt32 {
        get { return (int)Value; } set { Value = value; } }
    public bool ValueInt32Specified {
        get { return Value != null && Value is int; } set { } }

    [ProtoMember(2)]
    public float ValueSingle {
        get { return (float)Value; } set { Value = value; } }
    public bool ValueSingleSpecified {
        get { return Value != null && Value is float; } set { } }

    // etc for expected types
}

Isso é algo parecido com o que eu tinha em mente. Diz-me o que pensas. Naturalmente, eu teria que adicionar uma subclasse para cada tipo de valor Eu preciso de apoio. O que você acha? Existe uma maneira melhor, você vê quaisquer ineficiências com este método?

[ProtoContract, Serializable]
[ProtoInclude(1, typeof(Int32FieldData))]
public abstract class FieldDataBase : ISerializable
{
    [ProtoIgnore]
    public abstract object Value { get; set;}
    protected FieldDataBase()
    { }

    #region ISerializable Members
    protected FieldDataBase(SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge<FieldDataBase>(info, this);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize<FieldDataBase>(info, this);
    }

    #endregion
}

[ProtoContract, Serializable]
public class Int32FieldData : FieldDataBase
{
    [ProtoMember(1)]
    public int? Int32Value;

    [ProtoIgnore]
    public override object Value
    {
        get { return this.Int32Value.HasValue ? this.Int32Value : null; }
        set { this.Int32Value = (int?)value; }
    }
    public Int32FieldData() { }
    protected Int32FieldData(SerializationInfo info, StreamingContext context)
        :base(info, context)
    { }
}

encapsulamento direto parece funcionar bem sem sobrecarga adicional de todas as propriedades, da seguinte maneira:

[ProtoContract, Serializable]
public class ObjectWrapper : ISerializable
{
    public ObjectWrapper()
    { }
    [ProtoIgnore]
    public object Value
    {
        get
        {
            if (Int32Value.HasValue)
                return Int32Value.Value;
            else if (BinaryValue != null)
                return BinaryValue;
            else
                return StringValue;
        }
        set
        {
            if (value is int)
                this.Int32Value = (int)value;
            else if (value is byte[])
                this.BinaryValue = (byte[])value;
            else if (value is string)
                this.StringValue = (string)value;
        }
    }
    [ProtoMember(1)]
    private int? Int32Value;
    [ProtoMember(2)]
    private string StringValue;
    [ProtoMember(3)]
    private byte[] BinaryValue;
            // etc

    #region ISerializable Members
    protected ObjectWrapper(SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge<ObjectWrapper>(info, this);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize<ObjectWrapper>(info, this);
    }

    #endregion
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top