문제

다음 예에서 :

public class RowData
{
    public object[] Values;
}

public class FieldData
{
    public object Value;
}

Protobuf-Net 또는 Dotnet-Protobufs가 그러한 수업을 어떻게 처리하는지 궁금합니다. 나는 Protobuf-net에 더 익숙하기 때문에 실제로 가지고있는 것은 다음과 같습니다.

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

그러나 "적절한 기본 오브젝트 인코딩이 발견되지 않았다"는 오류가 발생합니다. 이 수업을 치료하는 쉬운 방법이 있습니까?

유스 케이스에 대해 더 자세히 설명하기 위해 :

이것은 원격에 사용되는 데이터 클래스의 스케일 다운 버전입니다. 따라서 본질적으로 다음과 같이 보입니다.

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

remoteObject.DoSomething(data);

참고 : 단순성을 위해 iserializable 구현을 생략했지만 예상대로입니다.

도움이 되었습니까?

해결책

(업데이트)

오른쪽; 위의 샘플의 주요 문제는 가치가있는 것입니다. 그들은 예외를 던지고있었습니다. 도서관 결함도있었습니다 (이제 고정되었습니다).

그러나 가장 간단한 접근법은입니다 Nullable<T> 패스 스루 속성 :

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

등 :

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

이것과 *지정된 접근법이 모두있었습니다 테스트, 그리고 이제 잘 작동합니다.

다른 팁

내가 유지하는 re protobuf-net :

여기의 문제는 가치 유형이 아닙니다 (종종 잘 처리합니다) - 개방형입니다. object 사용법은 단순히 어떤 데이터를 기대 해야하는지 모르고 인코딩/디코딩 방법을 알지 못합니다.

현재, 나는 그것을 처리 할 수있는 쉽고 깨끗한 방법을 생각할 수 없습니다. 계약 (데이터 계약, 프로토 계약 또는 일부 XML-Schemas)을 기반으로하는 다양한 공통 가치 유형 시나리오, 목록 및 모든 수준의 계층 구조를 처리하지만 단서.

아마도 당신이 사용 사례를 명확히 할 수 있다면 더 도움이 될 수 있습니까? 예를 들어, 위는 그다지 작동하지 않습니다 DataContractSerializer 또는 XmlSerializer 어느 하나...

RE DOTNET-PROTOBUFS; 나는 실제로 논평 할 수 없지만, 그것이 덜 용서할 것이라고 확신합니다. .proto 파일에서 생성 된 클래스와 함께 사용되기위한 것입니다. object 단순히 모델에 들어 가지 않을 것입니다 (Jon : 내가 틀렸다면 나를 수정하십시오).

더 많은 정보를 남기면 여기에 친절하게 의견을 게시 할 수 있습니까? 그래서 쉽게 찾을 수 있습니다 ... 또는 직접 메일을 내려 놓으십시오 (내 SO 프로필 참조).


편집 - 여기에 내가 염두에 두었던 것들이 있습니다 - 그것은 현재 작동하지 않지만 내일 (아마도) 이유를 알게 될 것입니다. 이론적으로 추가 회원은 모두 비공개 일 수 있습니다. 디버깅하는 동안 쉽게 만들려고 노력하고 있습니다. 이것은 추가 스토리지가 필요하지 않습니다. 내가 말했듯이, 오늘은 작동하지 않지만 그 이유를 알게 될 것입니다 ...

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

이것은 내가 생각했던 것과 같은 것입니다. 당신이 무슨 생각을하는지 제게 알려주세요. 당연히 지원 해야하는 각 값 유형에 대한 서브 클래스를 추가해야합니다. 어떻게 생각해? 더 나은 방법이 있습니까?이 방법에 비효율적 인 비효율이 있습니까?

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

직접 캡슐화는 다음과 같은 방식으로 모든 속성의 추가 오버 헤드없이 잘 작동하는 것 같습니다.

[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
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top