Los tampones de protocolo en C #: Tipos de Valores Cómo están encuadrados con los que comercia

StackOverflow https://stackoverflow.com/questions/562558

Pregunta

En los ejemplos siguientes:

public class RowData
{
    public object[] Values;
}

public class FieldData
{
    public object Value;
}

Tengo curiosidad de cómo sea protobuf-net o dotnet-protobufs se ocuparía de esas clases. Estoy más familiarizado con protobuf-net, así que lo que realmente tengo es:

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

Sin embargo me sale un error que dice "No codificación predeterminada del objeto encontrado adecuada". ¿Hay una manera fácil de tratar estas clases, que yo no soy consciente de?

Para elaborar más en el caso de uso:

Esta es una versión reducida de una clase de datos utilizados en la comunicación remota. Así que, esencialmente se parece a esto:

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

remoteObject.DoSomething(data);

Nota:. He omitido la aplicación ISerializable por simplicidad, pero es lo que se espera

¿Fue útil?

Solución

(actualizado)

Derecho; figurado a cabo ... el principal problema en mi ejemplo anterior era el valor-compradores; estaban tirando excepciones. También hubo algunos problemas técnicos de la biblioteca ( ahora fijo ).

Sin embargo, el enfoque más sencillo es Nullable<T> pasar-por propiedades:

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

etc, con:

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

Tanto ésta como el enfoque * especificado haber sido probado, y ahora funciona bien.

Otros consejos

Re-protobuf neto, que sostengo:

El tema aquí no es de valor tipos (que a menudo se encargará fino) - es el uso object abierta, lo que significa que simplemente no sabe qué datos se esperan, y por lo tanto cómo codificar / decodificar ella.

Por el momento, no puedo pensar en una manera fácil / limpia para manejar eso. Que se encargará de una serie de escenarios de tipo valor común, listas, y cualquier nivel de jerarquía basada en los contratos (contrato de datos, proto-contratos, o algunos xml esquemas), pero necesita un clave .

Tal vez si se puede aclarar el uso de los casos, podría ser capaz de ayudar más? Por ejemplo, lo anterior no quiere trabajar con muy DataContractSerializer o XmlSerializer bien ...

Re dotnet-protobufs; Realmente no puedo comentar, pero estoy bastante seguro de que sería aún menos tolerantes; se destina a ser utilizado con las clases generadas a partir de un archivo .proto, por lo object simplemente nunca entraría en el modelo (Jon: me corrija si estoy equivocado)

.

Si lo hace salir más información, podría usted amablemente publicar un comentario aquí? Así que se puede encontrar fácilmente ... Por otra parte, mándenme un correo directamente (ver mi perfil SO).


editar - aquí está la cosa hacky que tenía en mente - no está funcionando en este momento, pero voy a averiguar por qué mañana (probablemente). Tenga en cuenta que, en teoría, los miembros adicionales podrían ser todos privada - Sólo estoy tratando de hacer más fácil durante la depuración. Tenga en cuenta que esto no tiene ningún almacenamiento adicional. Como digo, no funciona hoy en día, pero debe - Voy a averiguar por qué ...

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

Esto es algo así como lo que tenía en mente. Déjame saber lo que piensas. Naturalmente tendría que añadir una subclase para cada tipo de valor que necesito para apoyar. ¿Qué piensas? ¿Hay una mejor manera, es lo que hay ineficiencias con 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)
    { }
}

encapsulación directa parece funcionar bien sin sobrecarga adicional de todas las propiedades, de la siguiente manera:

[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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top