المخازن المؤقتة في البروتوكول في C #: كيف يتم التعامل مع أنواع القيمة المحبطة

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

سؤال

في الأمثلة التالية:

public class RowData
{
    public object[] Values;
}

public class FieldData
{
    public object Value;
}

أنا فضولي كمثل إما Protobuf-net أو dotnet-protobufs سوف تتعامل مع هذه الفصول. أنا أكثر دراية بروتوكول صافي، لذلك ما لدي فعلا هو:

[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> خصائص Pass-thru:

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

كان كل هذا و * النهج المحدد اختبار, ، والآن تعمل بشكل جيد.

نصائح أخرى

إعادة Protobuf-Net، التي أمتلكها:

هذه المسألة هنا ليست أنواعا ذات قيمة (التي ستتعامل عليها في كثير من الأحيان بشكل جيد) - إنها مفتوحة object الاستخدام، مما يعني أنه ببساطة لا يعرف البيانات التي تتوقعها، وبالتالي كيفية تشفير / فك تشفيرها.

في الوقت الحالي، لا أستطيع التفكير في طريقة سهلة / نظيفة للتعامل مع ذلك. سوف تتعامل مع مجموعة من السيناريوهات المشتركة من نوع القيم، والقوائم، وأي مستوى من التسلسل الهرمي بناء على العقود (عقد البيانات، والعقود البروتو، أو بعض مخططات XML)، ولكنها تحتاج إلى فكرة.

ربما إذا كنت تستطيع توضيح حالة الاستخدام، فقد أكون قادرا على المساعدة أكثر؟ على سبيل المثال، ما سبق لن يعمل مع DataContractSerializer أو XmlSerializer إما...

إعادة dotnet-protobufs؛ لا أستطيع التعليق حقا، لكنني متأكد من أنه سيكون أقل تسامحا؛ من المقصود أن تستخدم مع الفصول المتولدة من ملف .proto، لذلك object لن يدخل ببساطة أبدا النموذج (جون: صحح لي إذا كنت مخطئا).

إذا تركت المزيد من المعلومات، فهل يمكنك نشر تعليق هنا؟ حتى أتمكن من العثور عليه بسهولة ... بدلا من ذلك، إسقاط لي بريد مباشرة (انظر لي شخصي).


تحرير - إليك الشيء المخراجر الذي أدلى به في الاعتبار - إنه لا يعمل في الوقت الحالي، لكنني سأكتشف لماذا غدا (ربما). لاحظ أنه من الناحية النظرية يمكن أن يكون الأعضاء الإضافي جميعا - أنا أحاول فقط أن أجعل الأمر سهلا أثناء تصحيح الأخطاء. لاحظ أن هذا لا يأخذ أي تخزين إضافي. كما أقول، فإنه لا يعمل اليوم، ولكن يجب أن ألقي ذلك لماذا ...

[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